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.DEVICE_TYPE_CONTROLLER; 21 import static com.android.server.uwb.data.UwbUciConstants.FIRA_VERSION_MAJOR_2; 22 import static com.android.server.uwb.data.UwbUciConstants.MAC_ADDRESSING_MODE_EXTENDED; 23 import static com.android.server.uwb.data.UwbUciConstants.MAC_ADDRESSING_MODE_SHORT; 24 import static com.android.server.uwb.data.UwbUciConstants.RANGING_DEVICE_ROLE_OBSERVER; 25 import static com.android.server.uwb.data.UwbUciConstants.REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS; 26 import static com.android.server.uwb.data.UwbUciConstants.ROUND_USAGE_OWR_AOA_MEASUREMENT; 27 import static com.android.server.uwb.data.UwbUciConstants.STATUS_CODE_OK; 28 import static com.android.server.uwb.data.UwbUciConstants.UWB_DEVICE_EXT_MAC_ADDRESS_LEN; 29 import static com.android.server.uwb.data.UwbUciConstants.UWB_DEVICE_SHORT_MAC_ADDRESS_LEN; 30 import static com.android.server.uwb.data.UwbUciConstants.UWB_SESSION_STATE_ACTIVE; 31 import static com.android.server.uwb.util.DataTypeConversionUtil.macAddressByteArrayToLong; 32 33 import static com.google.uwb.support.fira.FiraParams.FILTER_TYPE_APPLICATION; 34 import static com.google.uwb.support.fira.FiraParams.FILTER_TYPE_DEFAULT; 35 import static com.google.uwb.support.fira.FiraParams.FILTER_TYPE_NONE; 36 import static com.google.uwb.support.fira.FiraParams.MULTICAST_LIST_UPDATE_ACTION_ADD; 37 import static com.google.uwb.support.fira.FiraParams.MULTICAST_LIST_UPDATE_ACTION_DELETE; 38 import static com.google.uwb.support.fira.FiraParams.PROTOCOL_NAME; 39 import static com.google.uwb.support.fira.FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE; 40 import static com.google.uwb.support.fira.FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_32_BYTE; 41 import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG; 42 import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG; 43 44 import android.annotation.NonNull; 45 import android.annotation.Nullable; 46 import android.app.ActivityManager; 47 import android.app.AlarmManager; 48 import android.content.AttributionSource; 49 import android.os.Handler; 50 import android.os.IBinder; 51 import android.os.Looper; 52 import android.os.Message; 53 import android.os.PersistableBundle; 54 import android.os.RemoteException; 55 import android.os.Trace; 56 import android.util.Log; 57 import android.util.Pair; 58 import android.uwb.IUwbAdapter; 59 import android.uwb.IUwbRangingCallbacks; 60 import android.uwb.RangingChangeReason; 61 import android.uwb.SessionHandle; 62 import android.uwb.UwbAddress; 63 64 import androidx.annotation.GuardedBy; 65 import androidx.annotation.VisibleForTesting; 66 67 import com.android.modules.utils.build.SdkLevel; 68 import com.android.server.uwb.advertisement.UwbAdvertiseManager; 69 import com.android.server.uwb.data.DtTagUpdateRangingRoundsStatus; 70 import com.android.server.uwb.data.UwbDeviceInfoResponse; 71 import com.android.server.uwb.data.UwbDlTDoAMeasurement; 72 import com.android.server.uwb.data.UwbMulticastListUpdateStatus; 73 import com.android.server.uwb.data.UwbOwrAoaMeasurement; 74 import com.android.server.uwb.data.UwbRadarData; 75 import com.android.server.uwb.data.UwbRangingData; 76 import com.android.server.uwb.data.UwbTwoWayMeasurement; 77 import com.android.server.uwb.data.UwbUciConstants; 78 import com.android.server.uwb.jni.INativeUwbManager; 79 import com.android.server.uwb.jni.NativeUwbManager; 80 import com.android.server.uwb.params.TlvUtil; 81 import com.android.server.uwb.proto.UwbStatsLog; 82 import com.android.server.uwb.rftest.RfNotificationEvent; 83 import com.android.server.uwb.util.ArrayUtils; 84 import com.android.server.uwb.util.DataTypeConversionUtil; 85 import com.android.server.uwb.util.LruList; 86 import com.android.server.uwb.util.UwbUtil; 87 import com.android.uwb.fusion.UwbFilterEngine; 88 import com.android.uwb.fusion.pose.ApplicationPoseSource; 89 import com.android.uwb.fusion.pose.IPoseSource; 90 91 import com.google.common.collect.Sets; 92 import com.google.uwb.support.aliro.AliroOpenRangingParams; 93 import com.google.uwb.support.aliro.AliroParams; 94 import com.google.uwb.support.aliro.AliroRangingStartedParams; 95 import com.google.uwb.support.aliro.AliroRangingStoppedParams; 96 import com.google.uwb.support.aliro.AliroSpecificationParams; 97 import com.google.uwb.support.aliro.AliroStartRangingParams; 98 import com.google.uwb.support.base.Params; 99 import com.google.uwb.support.ccc.CccOpenRangingParams; 100 import com.google.uwb.support.ccc.CccParams; 101 import com.google.uwb.support.ccc.CccRangingReconfiguredParams; 102 import com.google.uwb.support.ccc.CccRangingStartedParams; 103 import com.google.uwb.support.ccc.CccRangingStoppedParams; 104 import com.google.uwb.support.ccc.CccSpecificationParams; 105 import com.google.uwb.support.ccc.CccStartRangingParams; 106 import com.google.uwb.support.dltdoa.DlTDoARangingRoundsUpdate; 107 import com.google.uwb.support.dltdoa.DlTDoARangingRoundsUpdateStatus; 108 import com.google.uwb.support.fira.FiraDataTransferPhaseConfig; 109 import com.google.uwb.support.fira.FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList; 110 import com.google.uwb.support.fira.FiraHybridSessionControleeConfig; 111 import com.google.uwb.support.fira.FiraHybridSessionControllerConfig; 112 import com.google.uwb.support.fira.FiraOnControleeAddRemoveParams; 113 import com.google.uwb.support.fira.FiraOpenSessionParams; 114 import com.google.uwb.support.fira.FiraParams; 115 import com.google.uwb.support.fira.FiraPoseUpdateParams; 116 import com.google.uwb.support.fira.FiraProtocolVersion; 117 import com.google.uwb.support.fira.FiraRangingReconfigureParams; 118 import com.google.uwb.support.fira.FiraSpecificationParams; 119 import com.google.uwb.support.generic.GenericSpecificationParams; 120 import com.google.uwb.support.oemextension.AdvertisePointedTarget; 121 import com.google.uwb.support.oemextension.SessionConfigParams; 122 import com.google.uwb.support.oemextension.SessionStatus; 123 import com.google.uwb.support.rftest.RfTestParams; 124 import com.google.uwb.support.rftest.RfTestSessionStatus; 125 import com.google.uwb.support.rftest.RfTestStartSessionParams; 126 127 import java.io.Closeable; 128 import java.io.FileDescriptor; 129 import java.io.PrintWriter; 130 import java.nio.ByteBuffer; 131 import java.nio.ByteOrder; 132 import java.util.ArrayList; 133 import java.util.Arrays; 134 import java.util.Collection; 135 import java.util.Comparator; 136 import java.util.List; 137 import java.util.Map; 138 import java.util.NoSuchElementException; 139 import java.util.Optional; 140 import java.util.Set; 141 import java.util.SortedMap; 142 import java.util.TreeMap; 143 import java.util.concurrent.Callable; 144 import java.util.concurrent.ConcurrentHashMap; 145 import java.util.concurrent.ExecutionException; 146 import java.util.concurrent.ExecutorService; 147 import java.util.concurrent.Executors; 148 import java.util.concurrent.FutureTask; 149 import java.util.concurrent.TimeUnit; 150 import java.util.concurrent.TimeoutException; 151 import java.util.stream.Collectors; 152 153 public class UwbSessionManager implements INativeUwbManager.SessionNotification, 154 ActivityManager.OnUidImportanceListener { 155 156 private static final String TAG = "UwbSessionManager"; 157 private static final byte OPERATION_TYPE_INIT_SESSION = 0; 158 private static final int UWB_HUS_CONTROLLER_PHASE_LIST_EXTENDED_MAC_ADDRESS_SIZE = 17; 159 private static final int UWB_HUS_CONTROLEE_PHASE_LIST_SIZE = 4; 160 161 @VisibleForTesting 162 public static final int SESSION_OPEN_RANGING = 1; 163 @VisibleForTesting 164 public static final int SESSION_START_RANGING = 2; 165 @VisibleForTesting 166 public static final int SESSION_STOP_RANGING = 3; 167 @VisibleForTesting 168 public static final int SESSION_RECONFIG_RANGING = 4; 169 @VisibleForTesting 170 public static final int SESSION_DEINIT = 5; 171 @VisibleForTesting 172 public static final int SESSION_ON_DEINIT = 6; 173 @VisibleForTesting 174 public static final int SESSION_SEND_DATA = 7; 175 @VisibleForTesting 176 public static final int SESSION_UPDATE_DT_TAG_RANGING_ROUNDS = 8; 177 @VisibleForTesting 178 public static final int SESSION_SET_HUS_CONTROLLER_CONFIG = 9; 179 @VisibleForTesting 180 public static final int SESSION_SET_HUS_CONTROLEE_CONFIG = 10; 181 @VisibleForTesting 182 public static final int SESSION_DATA_TRANSFER_PHASE_CONFIG = 11; 183 @VisibleForTesting 184 public static final int SESSION_RF_TEST_CMD = 12; 185 @VisibleForTesting 186 public static final int SESSION_STOP_RF_TEST_SESSION = 13; 187 188 // TODO: don't expose the internal field for testing. 189 @VisibleForTesting 190 final ConcurrentHashMap<SessionHandle, UwbSession> mSessionTable = new ConcurrentHashMap(); 191 // Used for storing recently closed sessions for debugging purposes. 192 final LruList<UwbSession> mDbgRecentlyClosedSessions = new LruList<>(5); 193 final ConcurrentHashMap<Integer, List<UwbSession>> mNonPrivilegedUidToFiraSessionsTable = 194 new ConcurrentHashMap(); 195 final ConcurrentHashMap<Integer, Integer> mSessionTokenMap = new ConcurrentHashMap<>(); 196 private final ActivityManager mActivityManager; 197 private final NativeUwbManager mNativeUwbManager; 198 private final UwbMetrics mUwbMetrics; 199 private final UwbConfigurationManager mConfigurationManager; 200 private final UwbSessionNotificationManager mSessionNotificationManager; 201 private final UwbAdvertiseManager mAdvertiseManager; 202 private final UwbInjector mUwbInjector; 203 private final AlarmManager mAlarmManager; 204 private final Looper mLooper; 205 private final EventTask mEventTask; 206 UwbSessionManager( UwbConfigurationManager uwbConfigurationManager, NativeUwbManager nativeUwbManager, UwbMetrics uwbMetrics, UwbAdvertiseManager uwbAdvertiseManager, UwbSessionNotificationManager uwbSessionNotificationManager, UwbInjector uwbInjector, AlarmManager alarmManager, ActivityManager activityManager, Looper serviceLooper)207 public UwbSessionManager( 208 UwbConfigurationManager uwbConfigurationManager, 209 NativeUwbManager nativeUwbManager, UwbMetrics uwbMetrics, 210 UwbAdvertiseManager uwbAdvertiseManager, 211 UwbSessionNotificationManager uwbSessionNotificationManager, 212 UwbInjector uwbInjector, AlarmManager alarmManager, ActivityManager activityManager, 213 Looper serviceLooper) { 214 mNativeUwbManager = nativeUwbManager; 215 mNativeUwbManager.setSessionListener(this); 216 mUwbMetrics = uwbMetrics; 217 mAdvertiseManager = uwbAdvertiseManager; 218 mConfigurationManager = uwbConfigurationManager; 219 mSessionNotificationManager = uwbSessionNotificationManager; 220 mUwbInjector = uwbInjector; 221 mAlarmManager = alarmManager; 222 mActivityManager = activityManager; 223 mLooper = serviceLooper; 224 mEventTask = new EventTask(serviceLooper); 225 registerUidImportanceTransitions(); 226 } 227 228 @Override onUidImportance(final int uid, final int importance)229 public void onUidImportance(final int uid, final int importance) { 230 Handler handler = new Handler(mLooper); 231 handler.post(() -> { 232 synchronized (mNonPrivilegedUidToFiraSessionsTable) { 233 List<UwbSession> uwbSessions = mNonPrivilegedUidToFiraSessionsTable.get(uid); 234 // Not a uid in the watch list 235 if (uwbSessions == null) return; 236 boolean newModeHasNonPrivilegedFgAppOrService = 237 UwbInjector.isForegroundAppOrServiceImportance(importance); 238 for (UwbSession uwbSession : uwbSessions) { 239 // already at correct state. 240 if (newModeHasNonPrivilegedFgAppOrService 241 == uwbSession.hasNonPrivilegedFgAppOrService()) { 242 continue; 243 } 244 uwbSession.setHasNonPrivilegedFgAppOrService( 245 newModeHasNonPrivilegedFgAppOrService); 246 int sessionId = uwbSession.getSessionId(); 247 Log.i(TAG, "App state change for session " + sessionId + ". IsFg: " 248 + newModeHasNonPrivilegedFgAppOrService); 249 // Reconfigure the session based on the new fg/bg state 250 Log.i(TAG, "Session " + sessionId 251 + " reconfiguring ntf control due to app state change"); 252 uwbSession.reconfigureFiraSessionOnFgStateChange(); 253 // Recalculate session priority based on the new fg/bg state. 254 if (!uwbSession.mSessionPriorityOverride) { 255 int newSessionPriority = uwbSession.calculateSessionPriority(); 256 Log.i(TAG, "Session " + sessionId 257 + " recalculating session priority, new priority: " 258 + newSessionPriority); 259 uwbSession.setStackSessionPriority(newSessionPriority); 260 } 261 } 262 } 263 }); 264 } 265 266 // Detect UIDs going foreground/background registerUidImportanceTransitions()267 private void registerUidImportanceTransitions() { 268 mActivityManager.addOnUidImportanceListener( 269 UwbSessionManager.this, IMPORTANCE_FOREGROUND_SERVICE); 270 } 271 hasAllRangingResultError(@onNull UwbRangingData rangingData)272 private static boolean hasAllRangingResultError(@NonNull UwbRangingData rangingData) { 273 if (rangingData.getRangingMeasuresType() 274 == UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY) { 275 for (UwbTwoWayMeasurement measure : rangingData.getRangingTwoWayMeasures()) { 276 if (measure.isStatusCodeOk()) { 277 return false; 278 } 279 } 280 } else if (rangingData.getRangingMeasuresType() 281 == UwbUciConstants.RANGING_MEASUREMENT_TYPE_OWR_AOA) { 282 UwbOwrAoaMeasurement measure = rangingData.getRangingOwrAoaMeasure(); 283 if (measure.getRangingStatus() == UwbUciConstants.STATUS_CODE_OK) { 284 return false; 285 } 286 } else if (rangingData.getRangingMeasuresType() 287 == UwbUciConstants.RANGING_MEASUREMENT_TYPE_DL_TDOA) { 288 for (UwbDlTDoAMeasurement measure : rangingData.getUwbDlTDoAMeasurements()) { 289 if (measure.getStatus() == STATUS_CODE_OK) { 290 return false; 291 } 292 } 293 } 294 return true; 295 } 296 handlePerControleeErrorStreakTimers(@onNull UwbRangingData rangingData, @NonNull UwbSession uwbSession)297 private void handlePerControleeErrorStreakTimers(@NonNull UwbRangingData rangingData, 298 @NonNull UwbSession uwbSession) { 299 // TODO(b/343508180): The outer conditional is a workaround for inconsistent behavior on 300 // cuttlefish (see b/343495601). Remove and/or refactor once this behavior is fixed. 301 if (rangingData.getNoOfRangingMeasures() == 0) { 302 // If we got no ranging measurements, start a session-level error streak timer. 303 uwbSession.startRangingResultErrorStreakTimerIfNotSet(); 304 } else { 305 for (UwbTwoWayMeasurement measure : rangingData.getRangingTwoWayMeasures()) { 306 UwbAddress address = UwbAddress.fromBytes(measure.getMacAddress()); 307 if (measure.isStatusCodeOk()) { 308 uwbSession.stopRangingResultErrorStreakTimerIfSet(address); 309 uwbSession.stopRangingResultErrorStreakTimerIfSet(); 310 } else { 311 uwbSession.startRangingResultErrorStreakTimerIfNotSet(address); 312 } 313 } 314 } 315 } 316 handlePerSessionErrorStreakTimer(@onNull UwbRangingData rangingData, @NonNull UwbSession uwbSession)317 private void handlePerSessionErrorStreakTimer(@NonNull UwbRangingData rangingData, 318 @NonNull UwbSession uwbSession) { 319 if (hasAllRangingResultError(rangingData)) { 320 uwbSession.startRangingResultErrorStreakTimerIfNotSet(); 321 } else { 322 uwbSession.stopRangingResultErrorStreakTimerIfSet(); 323 } 324 } 325 handleRangingResultErrorStreakTimers(@onNull UwbRangingData rangingData, @NonNull UwbSession uwbSession)326 private void handleRangingResultErrorStreakTimers(@NonNull UwbRangingData rangingData, 327 @NonNull UwbSession uwbSession) { 328 if (!mUwbInjector.getDeviceConfigFacade().isRangingErrorStreakTimerEnabled() 329 || uwbSession.mRangingErrorStreakTimeoutMs 330 == UwbSession.RANGING_RESULT_ERROR_NO_TIMEOUT) { 331 return; 332 } 333 334 boolean isDeviceControllerOfTwoWayRangingSession = rangingData.getRangingMeasuresType() 335 == UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY 336 && uwbSession.getDeviceType() == DEVICE_TYPE_CONTROLLER; 337 if (isDeviceControllerOfTwoWayRangingSession) { 338 handlePerControleeErrorStreakTimers(rangingData, uwbSession); 339 } else { 340 handlePerSessionErrorStreakTimer(rangingData, uwbSession); 341 } 342 } 343 344 @Override onRangeDataNotificationReceived(UwbRangingData rangingData)345 public void onRangeDataNotificationReceived(UwbRangingData rangingData) { 346 Trace.beginSection("UWB#onRangeDataNotificationReceived"); 347 long sessionId = rangingData.getSessionId(); 348 UwbSession uwbSession = getUwbSession((int) sessionId); 349 if (uwbSession != null) { 350 // TODO: b/268065070 Include UWB logs for both filtered and unfiltered data. 351 mSessionNotificationManager.onRangingResult(uwbSession, rangingData); 352 processRangeData(rangingData, uwbSession); 353 handleRangingResultErrorStreakTimers(rangingData, uwbSession); 354 } else { 355 Log.i(TAG, "Session is not initialized or Ranging Data is Null"); 356 } 357 Trace.endSection(); 358 } 359 360 /* Notification of received data over UWB to Application*/ 361 @Override onDataReceived( long sessionId, int status, long sequenceNum, byte[] address, byte[] data)362 public void onDataReceived( 363 long sessionId, int status, long sequenceNum, byte[] address, byte[] data) { 364 Log.d(TAG, "onDataReceived(): Received data packet - " 365 + "Address: " + UwbUtil.toHexString(address) 366 + ", Data: " + UwbUtil.toHexString(data) 367 + ", sessionId: " + sessionId 368 + ", status: " + status 369 + ", sequenceNum: " + sequenceNum); 370 371 UwbSession uwbSession = getUwbSession((int) sessionId); 372 if (uwbSession == null) { 373 Log.e(TAG, "onDataReceived(): Received data for unknown sessionId = " + sessionId); 374 return; 375 } 376 377 // Size of address in the UCI Packet for DATA_MESSAGE_RCV is always expected to be 8 378 // (EXTENDED_ADDRESS_BYTE_LENGTH). It can contain the MacAddress in short format however 379 // (2 LSB with MacAddress, 6 MSB zeroed out). 380 if (address.length != UWB_DEVICE_EXT_MAC_ADDRESS_LEN) { 381 Log.e(TAG, "onDataReceived(): Received data for sessionId = " + sessionId 382 + ", with unexpected MacAddress length = " + address.length); 383 return; 384 } 385 mUwbMetrics.logDataRx(uwbSession, status); 386 387 Long longAddress = macAddressByteArrayToLong(address); 388 UwbAddress uwbAddress = UwbAddress.fromBytes(address); 389 390 // When the data packet is received on a non OWR-for-AoA ranging session, send it to the 391 // higher layer. For the OWR-for-AoA ranging session, the data packet is only sent when the 392 // received SESSION_INFO_NTF indicate this Observer device is pointing to an Advertiser. 393 if (uwbSession.getRangingRoundUsage() != ROUND_USAGE_OWR_AOA_MEASUREMENT) { 394 mSessionNotificationManager.onDataReceived( 395 uwbSession, uwbAddress, new PersistableBundle(), data); 396 return; 397 } 398 399 ReceivedDataInfo info = new ReceivedDataInfo(); 400 info.sessionId = sessionId; 401 info.status = status; 402 info.sequenceNum = sequenceNum; 403 info.address = longAddress; 404 info.payload = data; 405 406 uwbSession.addReceivedDataInfo(info); 407 } 408 409 /* Notification of data send status */ 410 @Override onDataSendStatus( long sessionId, int dataTransferStatus, long sequenceNum, int txCount)411 public void onDataSendStatus( 412 long sessionId, int dataTransferStatus, long sequenceNum, int txCount) { 413 Log.d(TAG, "onDataSendStatus(): Received data send status - " 414 + ", sessionId: " + sessionId 415 + ", status: " + dataTransferStatus 416 + ", sequenceNum: " + sequenceNum 417 + ", txCount: " + txCount); 418 419 UwbSession uwbSession = getUwbSession((int) sessionId); 420 if (uwbSession == null) { 421 Log.e(TAG, "onDataSendStatus(): Received data send status for unknown sessionId = " 422 + sessionId); 423 return; 424 } 425 426 SendDataInfo sendDataInfo = uwbSession.getSendDataInfo(sequenceNum); 427 if (sendDataInfo == null) { 428 Log.e(TAG, "onDataSendStatus(): No SendDataInfo found for data packet (sessionId = " 429 + sessionId + ", sequenceNum = " + sequenceNum + ")"); 430 return; 431 } 432 433 // A note on status - earlier spec versions had the same status value (0x1) as an error, 434 // the code is written as per recent spec versions (v2.0.0_0.0.9r0). 435 if (dataTransferStatus == UwbUciConstants.STATUS_CODE_DATA_TRANSFER_REPETITION_OK 436 || dataTransferStatus == UwbUciConstants.STATUS_CODE_DATA_TRANSFER_OK) { 437 mSessionNotificationManager.onDataSent( 438 uwbSession, sendDataInfo.remoteDeviceAddress, sendDataInfo.params); 439 } else { 440 mSessionNotificationManager.onDataSendFailed( 441 uwbSession, sendDataInfo.remoteDeviceAddress, dataTransferStatus, 442 sendDataInfo.params); 443 uwbSession.removeSendDataInfo(sequenceNum); 444 } 445 // when transmission count equals to data repetition count, SendDataInfo will be removed for 446 // the particular sequence number 447 if (txCount >= (uwbSession.getDataRepetitionCount() + 1) 448 && dataTransferStatus == UwbUciConstants.STATUS_CODE_DATA_TRANSFER_OK) { 449 uwbSession.removeSendDataInfo(sequenceNum); 450 } 451 } 452 453 @Override onRadarDataMessageReceived(UwbRadarData radarData)454 public void onRadarDataMessageReceived(UwbRadarData radarData) { 455 Trace.beginSection("UWB#onRadarDataMessageReceived"); 456 long sessionId = radarData.sessionId; 457 UwbSession uwbSession = getUwbSession((int) sessionId); 458 if (uwbSession != null) { 459 mSessionNotificationManager.onRadarDataMessageReceived(uwbSession, radarData); 460 } else { 461 Log.i(TAG, "Session is not initialized or Radar Data is Null"); 462 } 463 Trace.endSection(); 464 } 465 466 @Override onDataTransferPhaseConfigNotificationReceived(long sessionId, int dataTransferPhaseConfigStatus)467 public void onDataTransferPhaseConfigNotificationReceived(long sessionId, 468 int dataTransferPhaseConfigStatus) { 469 Log.d(TAG, "onDataTransferPhaseConfigNotificationReceived:" 470 + ", sessionId: " + sessionId 471 + ", status: " + dataTransferPhaseConfigStatus); 472 473 UwbSession uwbSession = getUwbSession((int) sessionId); 474 if (uwbSession == null) { 475 Log.e(TAG, "onDataTransferPhaseConfigNotificationReceived: Received data transfer" 476 + "config notification for unknown sessionId = " + sessionId); 477 return; 478 } 479 480 if (dataTransferPhaseConfigStatus 481 == UwbUciConstants.STATUS_CODE_DATA_TRANSFER_PHASE_CONFIG_DTPCM_CONFIG_SUCCESS) { 482 mSessionNotificationManager.onDataTransferPhaseConfigured( 483 uwbSession, dataTransferPhaseConfigStatus); 484 } else { 485 mSessionNotificationManager.onDataTransferPhaseConfigFailed( 486 uwbSession, dataTransferPhaseConfigStatus); 487 } 488 } 489 490 /** Updates pose information if the session is using an ApplicationPoseSource */ updatePose(SessionHandle sessionHandle, PersistableBundle params)491 public void updatePose(SessionHandle sessionHandle, PersistableBundle params) { 492 int sessionId = getSessionId(sessionHandle); 493 UwbSession uwbSession = getUwbSession(sessionId); 494 495 if (uwbSession == null) { 496 // Session doesn't exist yet/anymore. 497 return; 498 } 499 500 uwbSession.updatePose(FiraPoseUpdateParams.fromBundle(params)); 501 } 502 503 @VisibleForTesting 504 static final class ReceivedDataInfo { 505 public long sessionId; 506 public int status; 507 public long sequenceNum; 508 public long address; 509 public byte[] payload; 510 } 511 512 @Override onMulticastListUpdateNotificationReceived( UwbMulticastListUpdateStatus multicastListUpdateStatus)513 public void onMulticastListUpdateNotificationReceived( 514 UwbMulticastListUpdateStatus multicastListUpdateStatus) { 515 Log.d(TAG, "onMulticastListUpdateNotificationReceived"); 516 UwbSession uwbSession = getUwbSession((int) multicastListUpdateStatus.getSessionId()); 517 if (uwbSession == null) { 518 Log.d(TAG, "onMulticastListUpdateNotificationReceived - invalid session"); 519 return; 520 } 521 522 uwbSession.setMulticastListUpdateStatus(multicastListUpdateStatus); 523 524 int actionStatus = UwbUciConstants.STATUS_CODE_OK; 525 for (int i = 0; i < multicastListUpdateStatus.getNumOfControlee(); i++) { 526 actionStatus = multicastListUpdateStatus.getStatus()[i]; 527 // Action - delete controlee, State - Active 528 if (actionStatus == UwbUciConstants.STATUS_CODE_OK) { 529 if (uwbSession.getOperationType() == SESSION_RECONFIG_RANGING) { 530 synchronized (uwbSession.getWaitObj()) { 531 uwbSession.getWaitObj().blockingNotify(); 532 } 533 break; 534 } 535 } else { 536 // Handle the failure case for adding a controlee 537 mSessionNotificationManager.onControleeAddFailed( 538 uwbSession, multicastListUpdateStatus.getControleeUwbAddresses()[i], 539 actionStatus); 540 } 541 542 } 543 if (actionStatus != UwbUciConstants.STATUS_CODE_OK) { 544 mSessionNotificationManager.onRangingReconfigureFailed( 545 uwbSession, actionStatus); 546 } 547 } 548 549 @Override onRfTestNotificationReceived(RfNotificationEvent rfNotificationEvent)550 public void onRfTestNotificationReceived(RfNotificationEvent rfNotificationEvent) { 551 UwbSession uwbSession = getUwbSession(RfTestParams.SESSION_ID_RFTEST); 552 if (uwbSession == null) { 553 Log.d(TAG, "UwbSession doesn't exist for SESSION_ID_RFTEST"); 554 return; 555 } 556 557 mSessionNotificationManager.onRfTestNotificationReceived(uwbSession, rfNotificationEvent); 558 } 559 560 @Override onSessionStatusNotificationReceived(long sessionId, int sessionToken, int state, int reasonCode)561 public void onSessionStatusNotificationReceived(long sessionId, int sessionToken, 562 int state, int reasonCode) { 563 Log.i(TAG, "onSessionStatusNotificationReceived - Session ID : " + sessionId 564 + ", sessionToken: " + sessionToken + ", state : " 565 + UwbSessionNotificationHelper.getSessionStateString(state) 566 + ", reasonCode:" + reasonCode); 567 UwbSession uwbSession = getUwbSession((int) sessionId); 568 569 if (uwbSession == null) { 570 Log.d(TAG, "onSessionStatusNotificationReceived - invalid session"); 571 return; 572 } 573 574 int prevState = uwbSession.getSessionState(); 575 setCurrentSessionState((int) sessionId, state); 576 577 if ((uwbSession.getOperationType() == SESSION_ON_DEINIT 578 && state == UwbUciConstants.UWB_SESSION_STATE_IDLE) 579 || (uwbSession.getOperationType() == SESSION_STOP_RANGING 580 && state == UwbUciConstants.UWB_SESSION_STATE_IDLE 581 && reasonCode != REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS)) { 582 Log.d(TAG, "Session status NTF is received due to in-band session state change"); 583 } 584 585 // Store the reasonCode before notifying on the waitObj. 586 synchronized (uwbSession.getWaitObj()) { 587 uwbSession.setLastSessionStatusNtfReasonCode(reasonCode); 588 uwbSession.getWaitObj().blockingNotify(); 589 } 590 591 //TODO : process only error handling in this switch function, b/218921154 592 switch (state) { 593 case UwbUciConstants.UWB_SESSION_STATE_IDLE: 594 if (prevState == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 595 // If session was stopped explicitly, then the onStopped() is sent from 596 // stopRanging method. 597 if (reasonCode != REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS) { 598 mSessionNotificationManager.onRangingStoppedWithUciReasonCode( 599 uwbSession, reasonCode); 600 mUwbMetrics.longRangingStopEvent(uwbSession); 601 } 602 } else if (prevState == UwbUciConstants.UWB_SESSION_STATE_IDLE) { 603 //mSessionNotificationManager.onRangingReconfigureFailed( 604 // uwbSession, reasonCode); 605 } 606 break; 607 case UwbUciConstants.UWB_SESSION_STATE_DEINIT: 608 mEventTask.execute(SESSION_ON_DEINIT, uwbSession); 609 break; 610 default: 611 break; 612 } 613 614 if (mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) { 615 String appPackageName = uwbSession.getAnyNonPrivilegedAppInAttributionSource() != null 616 ? uwbSession.getAnyNonPrivilegedAppInAttributionSource().getPackageName() 617 : uwbSession.getAttributionSource().getPackageName(); 618 PersistableBundle sessionStatusBundle = new SessionStatus.Builder() 619 .setSessionId(sessionId) 620 .setState(state) 621 .setReasonCode(reasonCode) 622 .setAppPackageName(appPackageName) 623 .setSessiontoken(sessionToken) 624 .setProtocolName(uwbSession.getProtocolName()) 625 .build() 626 .toBundle(); 627 try { 628 mUwbInjector.getUwbServiceCore().getOemExtensionCallback() 629 .onSessionStatusNotificationReceived(sessionStatusBundle); 630 } catch (RemoteException e) { 631 Log.e(TAG, "Failed to send vendor notification", e); 632 } 633 } 634 } 635 setAppConfigurations(UwbSession uwbSession)636 private int setAppConfigurations(UwbSession uwbSession) { 637 if (uwbSession.getProtocolName().equals(FiraParams.PROTOCOL_NAME) 638 && uwbSession.getParams() instanceof FiraOpenSessionParams) { 639 FiraOpenSessionParams params = (FiraOpenSessionParams) uwbSession.getParams(); 640 if (mSessionTokenMap.containsKey(params.getReferenceSessionHandle())) { 641 uwbSession.updateFiraParamsForSessionTimeBase( 642 mSessionTokenMap.get(params.getReferenceSessionHandle())); 643 } 644 } 645 646 int status = mConfigurationManager.setAppConfigurations(uwbSession.getSessionId(), 647 uwbSession.getParams(), uwbSession.getChipId(), 648 getUwbsFiraProtocolVersion(uwbSession.getChipId())); 649 650 if (status == UwbUciConstants.STATUS_CODE_OK 651 && uwbSession.getProtocolName().equals(RfTestParams.PROTOCOL_NAME)) { 652 status = mConfigurationManager.setRfTestAppConfigurations(uwbSession.getSessionId(), 653 uwbSession.getParams(), uwbSession.getChipId()); 654 } 655 656 if (status == UwbUciConstants.STATUS_CODE_OK 657 && mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) { 658 try { 659 SessionConfigParams sessionConfigParams = new SessionConfigParams.Builder() 660 .setSessionId(uwbSession.getSessionId()) 661 .setSessiontoken( 662 mSessionTokenMap.getOrDefault(uwbSession.getSessionId(), 0)) 663 .setOpenSessionParamsBundle(uwbSession.getParams().toBundle()) 664 .build(); 665 status = mUwbInjector.getUwbServiceCore().getOemExtensionCallback() 666 .onSessionConfigurationReceived(sessionConfigParams.toBundle()); 667 } catch (RemoteException e) { 668 Log.e(TAG, "Failed to send vendor notification", e); 669 } 670 } 671 return status; 672 } 673 initSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName, Params params, IUwbRangingCallbacks rangingCallbacks, String chipId)674 public synchronized void initSession(AttributionSource attributionSource, 675 SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName, 676 Params params, IUwbRangingCallbacks rangingCallbacks, String chipId) 677 throws RemoteException { 678 Log.i(TAG, "initSession() - sessionId: " + sessionId + ", sessionHandle: " + sessionHandle 679 + ", sessionType: " + sessionType); 680 UwbSession uwbSession = createUwbSession(attributionSource, sessionHandle, sessionId, 681 sessionType, protocolName, params, rangingCallbacks, chipId); 682 // Check the attribution source chain to ensure that there are no 3p apps which are not in 683 // fg which can receive the ranging results. 684 AttributionSource nonPrivilegedAppAttrSource = 685 uwbSession.getAnyNonPrivilegedAppInAttributionSource(); 686 if (nonPrivilegedAppAttrSource != null) { 687 Log.d(TAG, "Found a 3p app/service in the attribution source of request: " 688 + nonPrivilegedAppAttrSource); 689 // TODO(b/211445008): Move this operation to uwb thread. 690 boolean hasNonPrivilegedFgAppOrService = mUwbInjector.isForegroundAppOrService( 691 nonPrivilegedAppAttrSource.getUid(), 692 nonPrivilegedAppAttrSource.getPackageName()); 693 uwbSession.setHasNonPrivilegedFgAppOrService(hasNonPrivilegedFgAppOrService); 694 if (!hasNonPrivilegedFgAppOrService) { 695 if (!mUwbInjector.getDeviceConfigFacade().isBackgroundRangingEnabled()) { 696 Log.e(TAG, "openRanging - System policy disallows for non fg 3p apps"); 697 rangingCallbacks.onRangingOpenFailed(sessionHandle, 698 RangingChangeReason.SYSTEM_POLICY, new PersistableBundle()); 699 return; 700 } else { 701 Log.d(TAG, "openRanging - System policy allows for non fg 3p apps"); 702 } 703 } 704 } 705 if (isExistedSession(sessionHandle) || isExistedSession(sessionId)) { 706 Log.i(TAG, "Duplicated session. SessionHandle: " + sessionHandle + ", SessionId: " 707 + sessionId); 708 rangingCallbacks.onRangingOpenFailed(sessionHandle, RangingChangeReason.BAD_PARAMETERS, 709 UwbSessionNotificationHelper.convertUciStatusToParam(protocolName, 710 UwbUciConstants.STATUS_CODE_ERROR_SESSION_DUPLICATE)); 711 mUwbMetrics.logRangingInitEvent(uwbSession, 712 UwbUciConstants.STATUS_CODE_ERROR_SESSION_DUPLICATE); 713 return; 714 } 715 716 boolean maxSessionsExceeded = false; 717 // TODO: getCccSessionCount and getFiraSessionCount should be chip specific 718 if (protocolName.equals(AliroParams.PROTOCOL_NAME) 719 && getAliroSessionCount() >= getMaxAliroSessionsNumber(chipId)) { 720 Log.i(TAG, "Max ALIRO Sessions Exceeded"); 721 // All ALIRO sessions have the same priority so there's no point in trying to make space 722 // if max sessions are already reached. 723 maxSessionsExceeded = true; 724 } else if (protocolName.equals(CccParams.PROTOCOL_NAME) 725 && getCccSessionCount() >= getMaxCccSessionsNumber(chipId)) { 726 Log.i(TAG, "Max CCC Sessions Exceeded"); 727 // All CCC sessions have the same priority so there's no point in trying to make space 728 // if max sessions are already reached. 729 maxSessionsExceeded = true; 730 } else if (protocolName.equals(FiraParams.PROTOCOL_NAME) 731 && getFiraSessionCount() >= getMaxFiraSessionsNumber(chipId)) { 732 Log.i(TAG, "Max Fira Sessions Exceeded"); 733 maxSessionsExceeded = !tryMakeSpaceForFiraSession( 734 uwbSession.getStackSessionPriority()); 735 } 736 737 if (!maxSessionsExceeded && getSessionCount() >= getMaxSupportedSessionCount(chipId)) { 738 maxSessionsExceeded = true; 739 Log.i(TAG, "Session count exceeds max supported Session count"); 740 } 741 742 if (maxSessionsExceeded) { 743 rangingCallbacks.onRangingOpenFailed(sessionHandle, 744 RangingChangeReason.MAX_SESSIONS_REACHED, 745 UwbSessionNotificationHelper.convertUciStatusToParam(protocolName, 746 UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED)); 747 mUwbMetrics.logRangingInitEvent(uwbSession, 748 UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED); 749 return; 750 } 751 752 try { 753 uwbSession.getBinder().linkToDeath(uwbSession, 0); 754 } catch (RemoteException e) { 755 uwbSession.binderDied(); 756 Log.e(TAG, "linkToDeath fail - sessionID : " + uwbSession.getSessionId()); 757 rangingCallbacks.onRangingOpenFailed(sessionHandle, RangingChangeReason.UNKNOWN, 758 UwbSessionNotificationHelper.convertUciStatusToParam(protocolName, 759 UwbUciConstants.STATUS_CODE_FAILED)); 760 mUwbMetrics.logRangingInitEvent(uwbSession, 761 UwbUciConstants.STATUS_CODE_FAILED); 762 removeSession(uwbSession); 763 return; 764 } 765 766 mSessionTable.put(sessionHandle, uwbSession); 767 addToNonPrivilegedUidToFiraSessionTableIfNecessary(uwbSession); 768 mEventTask.execute(SESSION_OPEN_RANGING, uwbSession); 769 return; 770 } 771 tryMakeSpaceForFiraSession(int priorityThreshold)772 private boolean tryMakeSpaceForFiraSession(int priorityThreshold) { 773 Optional<UwbSession> lowestPrioritySession = getSessionWithLowestPriorityByProtocol( 774 FiraParams.PROTOCOL_NAME); 775 if (!lowestPrioritySession.isPresent()) { 776 Log.w(TAG, 777 "New session blocked by max sessions exceeded, but list of sessions is " 778 + "empty"); 779 return false; 780 } 781 if (lowestPrioritySession.get().getStackSessionPriority() < priorityThreshold) { 782 return deInitDueToLowPriority(lowestPrioritySession.get().getSessionHandle()); 783 } 784 return false; 785 } 786 787 // TODO: use UwbInjector. 788 @VisibleForTesting createUwbSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName, Params params, IUwbRangingCallbacks iUwbRangingCallbacks, String chipId)789 UwbSession createUwbSession(AttributionSource attributionSource, SessionHandle sessionHandle, 790 int sessionId, byte sessionType, String protocolName, Params params, 791 IUwbRangingCallbacks iUwbRangingCallbacks, String chipId) { 792 return new UwbSession(attributionSource, sessionHandle, sessionId, sessionType, 793 protocolName, params, iUwbRangingCallbacks, chipId); 794 } 795 deInitSession(SessionHandle sessionHandle)796 public synchronized void deInitSession(SessionHandle sessionHandle) { 797 if (!isExistedSession(sessionHandle)) { 798 Log.i(TAG, "Not initialized session ID"); 799 return; 800 } 801 802 int sessionId = getSessionId(sessionHandle); 803 Log.i(TAG, "deinitSession() - sessionId: " + sessionId 804 + ", sessionHandle: " + sessionHandle); 805 mEventTask.execute(SESSION_DEINIT, sessionHandle, STATUS_CODE_OK); 806 return; 807 } 808 809 /** 810 * Logs and executes session de-init task with low priority being sent as the reason in 811 * ranging closed callback. 812 */ deInitDueToLowPriority(SessionHandle sessionHandle)813 private synchronized boolean deInitDueToLowPriority(SessionHandle sessionHandle) { 814 int sessionId = getSessionId(sessionHandle); 815 if (!isExistedSession(sessionHandle)) { 816 Log.w(TAG, "Session " + sessionId + " expected to exist but not found. " 817 + "Failed to de-initialize low priority session."); 818 return false; 819 } 820 821 Log.i(TAG, "deInitDueToLowPriority() - sessionId: " + sessionId 822 + ", sessionHandle: " + sessionHandle); 823 mEventTask.execute(SESSION_DEINIT, sessionHandle, 824 UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED); 825 return true; 826 } 827 startRanging(SessionHandle sessionHandle, @Nullable Params params)828 public synchronized void startRanging(SessionHandle sessionHandle, @Nullable Params params) { 829 if (!isExistedSession(sessionHandle)) { 830 Log.i(TAG, "Not initialized session ID"); 831 return; 832 } 833 834 int sessionId = getSessionId(sessionHandle); 835 Log.i(TAG, "startRanging() - sessionId: " + sessionId 836 + ", sessionHandle: " + sessionHandle); 837 838 UwbSession uwbSession = getUwbSession(sessionId); 839 840 int currentSessionState = getCurrentSessionState(sessionId); 841 if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_IDLE) { 842 if (uwbSession.getProtocolName().equals(AliroParams.PROTOCOL_NAME) 843 && params instanceof AliroStartRangingParams) { 844 AliroStartRangingParams aliroStartRangingParams = (AliroStartRangingParams) params; 845 Log.i(TAG, "startRanging() - update RAN multiplier: " 846 + aliroStartRangingParams.getRanMultiplier() 847 + ", stsIndex: " + aliroStartRangingParams.getStsIndex()); 848 // Need to update the RAN multiplier from the AliroStartRangingParams for an 849 // ALIRO session. 850 uwbSession.updateAliroParamsOnStart(aliroStartRangingParams); 851 } else if (uwbSession.getProtocolName().equals(CccParams.PROTOCOL_NAME) 852 && params instanceof CccStartRangingParams) { 853 CccStartRangingParams cccStartRangingParams = (CccStartRangingParams) params; 854 Log.i(TAG, "startRanging() - update RAN multiplier: " 855 + cccStartRangingParams.getRanMultiplier() 856 + ", stsIndex: " + cccStartRangingParams.getStsIndex()); 857 // Need to update the RAN multiplier from the CccStartRangingParams for CCC session. 858 uwbSession.updateCccParamsOnStart(cccStartRangingParams); 859 } else if (uwbSession.getProtocolName().equals(FiraParams.PROTOCOL_NAME)) { 860 // Need to update session priority if it changed. 861 uwbSession.updateFiraParamsOnStartIfChanged(); 862 } else if (uwbSession.getProtocolName().equals(RfTestParams.PROTOCOL_NAME)) { 863 if (params instanceof RfTestStartSessionParams) { 864 uwbSession.setRfTestStartSessionParams((RfTestStartSessionParams) params); 865 mEventTask.execute(SESSION_RF_TEST_CMD, uwbSession); 866 } 867 return; 868 } 869 mEventTask.execute(SESSION_START_RANGING, uwbSession); 870 } else if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 871 Log.i(TAG, "session is already ranging"); 872 mSessionNotificationManager.onRangingStartFailed( 873 uwbSession, UwbUciConstants.STATUS_CODE_REJECTED); 874 } else { 875 Log.i(TAG, "session can't start ranging"); 876 mSessionNotificationManager.onRangingStartFailed( 877 uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 878 mUwbMetrics.longRangingStartEvent(uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 879 } 880 } 881 handleRfTestCommand(UwbSession uwbSession)882 private void handleRfTestCommand(UwbSession uwbSession) { 883 RfTestStartSessionParams params = uwbSession.getRfTestStartSessionParams(); 884 // create task to send RF command 885 FutureTask<Integer> rfCommandTask = new FutureTask<>((Callable<Integer>) () -> { 886 int rfTestOperationType = params.getRfTestOperationType(); 887 int status = UwbUciConstants.STATUS_CODE_FAILED; 888 889 synchronized (uwbSession.getWaitObj()) { 890 switch (rfTestOperationType) { 891 case RfTestParams.TEST_PERIODIC_TX: 892 status = mNativeUwbManager.testPeriodicTx(params.getPsduData(), 893 uwbSession.getChipId()); 894 break; 895 case RfTestParams.TEST_PER_RX: 896 status = mNativeUwbManager.testPerRx(params.getPsduData(), 897 uwbSession.getChipId()); 898 break; 899 default: 900 Log.i(TAG, "Unknown RF command: " + rfTestOperationType); 901 } 902 903 if (status != UwbUciConstants.STATUS_CODE_OK) { 904 mSessionNotificationManager.onRangingStartFailed(uwbSession, status); 905 } else { 906 uwbSession.getWaitObj().blockingWait(); 907 908 RfTestSessionStatus rfTestSessionStatus = new RfTestSessionStatus.Builder() 909 .setRfTestOperationType(rfTestOperationType) 910 .setStatusCode(status).build(); 911 mSessionNotificationManager.onRangingStarted(uwbSession, 912 rfTestSessionStatus); 913 } 914 } 915 return status; 916 }); 917 918 // Execute task 919 int status = UwbUciConstants.STATUS_CODE_FAILED; 920 921 try { 922 status = mUwbInjector.runTaskOnSingleThreadExecutor(rfCommandTask, 923 IUwbAdapter.RF_TEST_OPERATION_THRESHOLD_MS); 924 } catch (TimeoutException e) { 925 Log.i(TAG, "Failed to send RF command: TIMEOUT"); 926 mSessionNotificationManager.onRangingStartFailed(uwbSession, status); 927 } catch (InterruptedException | ExecutionException e) { 928 e.printStackTrace(); 929 } 930 } 931 handleStopRfTest(UwbSession uwbSession)932 private void handleStopRfTest(UwbSession uwbSession) { 933 Trace.beginSection("UWB#handleStopRfTest"); 934 FutureTask<Integer> stopRfSessionTask = new FutureTask<>( 935 () -> { 936 int status = UwbUciConstants.STATUS_CODE_FAILED; 937 synchronized (uwbSession.getWaitObj()) { 938 status = mNativeUwbManager.stopRfTest(uwbSession.getChipId()); 939 if (status != UwbUciConstants.STATUS_CODE_OK) { 940 mSessionNotificationManager.onRangingStopFailed(uwbSession, 941 status); 942 return status; 943 } 944 945 uwbSession.getWaitObj().blockingWait(); 946 // After stop rf test session command, UWBS will go to IDLE state 947 if (uwbSession.getSessionState() 948 == UwbUciConstants.UWB_SESSION_STATE_IDLE) { 949 mSessionNotificationManager.onRangingStopped(uwbSession, 950 status); 951 } else { 952 status = UwbUciConstants.STATUS_CODE_FAILED; 953 mSessionNotificationManager.onRangingStopFailed(uwbSession, 954 status); 955 } 956 } 957 return status; 958 }); 959 960 961 int status = UwbUciConstants.STATUS_CODE_FAILED; 962 try { 963 status = mUwbInjector.runTaskOnSingleThreadExecutor(stopRfSessionTask, 964 IUwbAdapter.RF_TEST_OPERATION_THRESHOLD_MS); 965 } catch (TimeoutException e) { 966 Log.i(TAG, "Failed to Stop RF test - status : TIMEOUT"); 967 mSessionNotificationManager.onRangingStopFailed( 968 uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 969 } catch (InterruptedException | ExecutionException e) { 970 e.printStackTrace(); 971 } 972 Trace.endSection(); 973 } 974 stopRangingInternal(SessionHandle sessionHandle, boolean triggeredBySystemPolicy)975 private synchronized void stopRangingInternal(SessionHandle sessionHandle, 976 boolean triggeredBySystemPolicy) { 977 if (!isExistedSession(sessionHandle)) { 978 Log.i(TAG, "Not initialized session ID"); 979 return; 980 } 981 982 int sessionId = getSessionId(sessionHandle); 983 Log.i(TAG, "stopRanging() - sessionId: " + sessionId 984 + ", sessionHandle: " + sessionHandle); 985 986 UwbSession uwbSession = getUwbSession(sessionId); 987 int currentSessionState = getCurrentSessionState(sessionId); 988 989 //RF Test session 990 if (uwbSession.getProtocolName().equals(RfTestParams.PROTOCOL_NAME)) { 991 if (sessionId != RfTestParams.SESSION_ID_RFTEST) { 992 mSessionNotificationManager.onRangingStopped(uwbSession, 993 UwbUciConstants.STATUS_CODE_REJECTED); 994 } 995 996 if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 997 mEventTask.execute(SESSION_STOP_RF_TEST_SESSION, uwbSession); 998 } else { 999 mSessionNotificationManager.onRangingStopped(uwbSession, 1000 UwbUciConstants.STATUS_CODE_REJECTED); 1001 Log.i(TAG, "RF session is not in ACTIVE state"); 1002 } 1003 return; 1004 } 1005 1006 if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 1007 mEventTask.execute(SESSION_STOP_RANGING, uwbSession, triggeredBySystemPolicy ? 1 : 0); 1008 } else if (currentSessionState == UwbUciConstants.UWB_SESSION_STATE_IDLE) { 1009 Log.i(TAG, "session is already idle state"); 1010 mSessionNotificationManager.onRangingStopped(uwbSession, 1011 UwbUciConstants.STATUS_CODE_OK); 1012 mUwbMetrics.longRangingStopEvent(uwbSession); 1013 } else { 1014 mSessionNotificationManager.onRangingStopFailed(uwbSession, 1015 UwbUciConstants.STATUS_CODE_REJECTED); 1016 Log.i(TAG, "Not active session ID"); 1017 } 1018 } 1019 stopRanging(SessionHandle sessionHandle)1020 public synchronized void stopRanging(SessionHandle sessionHandle) { 1021 stopRangingInternal(sessionHandle, false /* triggeredBySystemPolicy */); 1022 } 1023 1024 /** 1025 * Get the UwbSession corresponding to the given UWB Session ID. This API returns {@code null} 1026 * when the UWB session is not found. 1027 */ 1028 @Nullable getUwbSession(int sessionId)1029 public UwbSession getUwbSession(int sessionId) { 1030 return mSessionTable.values() 1031 .stream() 1032 .filter(v -> v.getSessionId() == sessionId) 1033 .findAny() 1034 .orElse(null); 1035 } 1036 1037 /** 1038 * Get the UwbSession corresponding to the given UWB SessionHandle. This API returns 1039 * {@code null} when the UWB session is not found. 1040 */ 1041 @Nullable getUwbSession(SessionHandle sessionHandle)1042 private UwbSession getUwbSession(SessionHandle sessionHandle) { 1043 return mSessionTable.get(sessionHandle); 1044 } 1045 1046 /** 1047 * Get the Uwb Session ID corresponding to the given UWB Session Handle. This API returns 1048 * {@code null} when the UWB session ID is not found. 1049 */ 1050 @Nullable getSessionId(SessionHandle sessionHandle)1051 public Integer getSessionId(SessionHandle sessionHandle) { 1052 UwbSession session = mSessionTable.get(sessionHandle); 1053 if (session == null) return null; 1054 return session.getSessionId(); 1055 } 1056 getActiveSessionCount()1057 private int getActiveSessionCount() { 1058 return Math.toIntExact( 1059 mSessionTable.values() 1060 .stream() 1061 .filter(v -> v.getSessionState() == UwbUciConstants.DEVICE_STATE_ACTIVE) 1062 .count() 1063 ); 1064 } 1065 processRangeData(UwbRangingData rangingData, UwbSession uwbSession)1066 private void processRangeData(UwbRangingData rangingData, UwbSession uwbSession) { 1067 if (rangingData.getRangingMeasuresType() 1068 != UwbUciConstants.RANGING_MEASUREMENT_TYPE_OWR_AOA) { 1069 return; 1070 } 1071 1072 if (!isValidUwbSessionForOwrAoaRanging(uwbSession)) { 1073 return; 1074 } 1075 1076 // Record the OWR Aoa Measurement from the RANGE_DATA_NTF. 1077 UwbOwrAoaMeasurement uwbOwrAoaMeasurement = rangingData.getRangingOwrAoaMeasure(); 1078 mAdvertiseManager.updateAdvertiseTarget(uwbOwrAoaMeasurement); 1079 1080 byte[] macAddressBytes = getValidMacAddressFromOwrAoaMeasurement( 1081 rangingData, uwbOwrAoaMeasurement); 1082 if (macAddressBytes == null) { 1083 Log.i(TAG, "OwR Aoa UwbSession: Invalid MacAddress for remote device"); 1084 return; 1085 } 1086 1087 boolean advertisePointingResult = mAdvertiseManager.isPointedTarget(macAddressBytes); 1088 if (mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) { 1089 try { 1090 PersistableBundle pointedTargetBundle = new AdvertisePointedTarget.Builder() 1091 .setMacAddress(macAddressBytes) 1092 .setAdvertisePointingResult(advertisePointingResult) 1093 .build() 1094 .toBundle(); 1095 1096 advertisePointingResult = mUwbInjector 1097 .getUwbServiceCore() 1098 .getOemExtensionCallback() 1099 .onCheckPointedTarget(pointedTargetBundle); 1100 } catch (RemoteException e) { 1101 e.printStackTrace(); 1102 } 1103 } 1104 1105 if (advertisePointingResult) { 1106 // Use a loop to notify all the received application data payload(s) (in sequence number 1107 // order) for this OWR AOA ranging session. 1108 long macAddress = macAddressByteArrayToLong(macAddressBytes); 1109 UwbAddress uwbAddress = UwbAddress.fromBytes(macAddressBytes); 1110 1111 List<ReceivedDataInfo> receivedDataInfoList = uwbSession.getAllReceivedDataInfo( 1112 macAddress); 1113 if (receivedDataInfoList.isEmpty()) { 1114 Log.i(TAG, "OwR Aoa UwbSession: Application Payload data not found for" 1115 + " MacAddress = " + UwbUtil.toHexString(macAddress)); 1116 return; 1117 } 1118 1119 receivedDataInfoList.stream().forEach(r -> 1120 mSessionNotificationManager.onDataReceived( 1121 uwbSession, uwbAddress, new PersistableBundle(), r.payload)); 1122 mUwbMetrics.logDataToUpperLayer(uwbSession, receivedDataInfoList.size()); 1123 mAdvertiseManager.removeAdvertiseTarget(macAddress); 1124 } 1125 } 1126 1127 @Nullable getValidMacAddressFromOwrAoaMeasurement(UwbRangingData rangingData, UwbOwrAoaMeasurement uwbOwrAoaMeasurement)1128 private byte[] getValidMacAddressFromOwrAoaMeasurement(UwbRangingData rangingData, 1129 UwbOwrAoaMeasurement uwbOwrAoaMeasurement) { 1130 byte[] macAddress = uwbOwrAoaMeasurement.getMacAddress(); 1131 if (rangingData.getMacAddressMode() == MAC_ADDRESSING_MODE_SHORT) { 1132 return (macAddress.length == UWB_DEVICE_SHORT_MAC_ADDRESS_LEN) ? macAddress : null; 1133 } else if (rangingData.getMacAddressMode() == MAC_ADDRESSING_MODE_EXTENDED) { 1134 return (macAddress.length == UWB_DEVICE_EXT_MAC_ADDRESS_LEN) ? macAddress : null; 1135 } 1136 return null; 1137 } 1138 isExistedSession(SessionHandle sessionHandle)1139 public boolean isExistedSession(SessionHandle sessionHandle) { 1140 return (getSessionId(sessionHandle) != null); 1141 } 1142 isExistedSession(int sessionId)1143 public boolean isExistedSession(int sessionId) { 1144 return getUwbSession(sessionId) != null; 1145 } 1146 stopAllRanging()1147 public void stopAllRanging() { 1148 Log.d(TAG, "stopAllRanging()"); 1149 for (UwbSession uwbSession : mSessionTable.values()) { 1150 int status = mNativeUwbManager.stopRanging(uwbSession.getSessionId(), 1151 uwbSession.getChipId()); 1152 1153 if (status != UwbUciConstants.STATUS_CODE_OK) { 1154 Log.i(TAG, "stopAllRanging() - Session " + uwbSession.getSessionId() 1155 + " is failed to stop ranging"); 1156 } else { 1157 mUwbMetrics.longRangingStopEvent(uwbSession); 1158 uwbSession.setSessionState(UwbUciConstants.UWB_SESSION_STATE_IDLE); 1159 } 1160 } 1161 } 1162 deInitAllSession()1163 public synchronized void deInitAllSession() { 1164 Log.d(TAG, "deinitAllSession()"); 1165 for (UwbSession uwbSession : mSessionTable.values()) { 1166 handleOnDeInit(uwbSession); 1167 } 1168 1169 // Not resetting chip on UWB toggle off. 1170 // mNativeUwbManager.deviceReset(UwbUciConstants.UWBS_RESET); 1171 } 1172 handleOnDeInit(UwbSession uwbSession)1173 public synchronized void handleOnDeInit(UwbSession uwbSession) { 1174 if (!isExistedSession(uwbSession.getSessionHandle())) { 1175 Log.i(TAG, "onDeinit - Ignoring already deleted session " 1176 + uwbSession.getSessionId()); 1177 return; 1178 } 1179 Log.d(TAG, "onDeinit: " + uwbSession.getSessionId()); 1180 mSessionNotificationManager.onRangingClosedWithApiReasonCode(uwbSession, 1181 RangingChangeReason.SYSTEM_POLICY); 1182 mUwbMetrics.logRangingCloseEvent(uwbSession, UwbUciConstants.STATUS_CODE_OK); 1183 1184 // Reset all UWB session timers when the session is de-init. 1185 uwbSession.stopTimers(); 1186 removeSession(uwbSession); 1187 } 1188 setCurrentSessionState(int sessionId, int state)1189 public void setCurrentSessionState(int sessionId, int state) { 1190 UwbSession uwbSession = getUwbSession(sessionId); 1191 if (uwbSession != null) { 1192 uwbSession.setSessionState(state); 1193 } 1194 } 1195 getCurrentSessionState(int sessionId)1196 public int getCurrentSessionState(int sessionId) { 1197 UwbSession uwbSession = getUwbSession(sessionId); 1198 if (uwbSession != null) { 1199 return uwbSession.getSessionState(); 1200 } 1201 return UwbUciConstants.UWB_SESSION_STATE_ERROR; 1202 } 1203 getSessionCount()1204 public int getSessionCount() { 1205 return mSessionTable.size(); 1206 } 1207 getAliroSessionCount()1208 public long getAliroSessionCount() { 1209 return getProtocolSessionCount(AliroParams.PROTOCOL_NAME); 1210 } 1211 getCccSessionCount()1212 public long getCccSessionCount() { 1213 return getProtocolSessionCount(CccParams.PROTOCOL_NAME); 1214 } 1215 getFiraSessionCount()1216 public long getFiraSessionCount() { 1217 return getProtocolSessionCount(FiraParams.PROTOCOL_NAME); 1218 } 1219 getProtocolSessionCount(String protocolName)1220 private long getProtocolSessionCount(String protocolName) { 1221 return mSessionTable.values().stream().filter( 1222 s -> s.mProtocolName.equals(protocolName)).count(); 1223 } 1224 1225 /** Returns max number of ALIRO sessions possible on given chip. */ getMaxAliroSessionsNumber(String chipId)1226 public long getMaxAliroSessionsNumber(String chipId) { 1227 GenericSpecificationParams params = 1228 mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(chipId); 1229 if (params != null && params.getAliroSpecificationParams() != null) { 1230 return params.getAliroSpecificationParams().getMaxRangingSessionNumber(); 1231 } else { 1232 // Specification params are empty, return the default ALIRO max sessions value 1233 return AliroSpecificationParams.DEFAULT_MAX_RANGING_SESSIONS_NUMBER; 1234 } 1235 } 1236 1237 /** Returns max number of CCC sessions possible on given chip. */ getMaxCccSessionsNumber(String chipId)1238 public long getMaxCccSessionsNumber(String chipId) { 1239 GenericSpecificationParams params = 1240 mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(chipId); 1241 if (params != null && params.getCccSpecificationParams() != null) { 1242 return params.getCccSpecificationParams().getMaxRangingSessionNumber(); 1243 } else { 1244 // specification params are empty, return the default CCC max sessions value 1245 return CccSpecificationParams.DEFAULT_MAX_RANGING_SESSIONS_NUMBER; 1246 } 1247 } 1248 1249 /** Returns max number of Fira sessions possible on given chip. */ getMaxFiraSessionsNumber(String chipId)1250 public long getMaxFiraSessionsNumber(String chipId) { 1251 GenericSpecificationParams params = 1252 mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(chipId); 1253 if (params != null && params.getFiraSpecificationParams() != null) { 1254 return params.getFiraSpecificationParams().getMaxRangingSessionNumber(); 1255 } else { 1256 // specification params are empty, return the default Fira max sessions value 1257 return FiraSpecificationParams.DEFAULT_MAX_RANGING_SESSIONS_NUMBER; 1258 } 1259 } 1260 1261 /** Returns max supported session count possible on given chip. */ getMaxSupportedSessionCount(String chipId)1262 public long getMaxSupportedSessionCount(String chipId) { 1263 GenericSpecificationParams params = 1264 mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(chipId); 1265 return (params != null) 1266 ? params.getMaxSupportedSessionCount() 1267 : getMaxFiraSessionsNumber(chipId) + getMaxCccSessionsNumber(chipId); 1268 } 1269 1270 /** Gets the session with the lowest session priority among all sessions with given protocol. */ getSessionWithLowestPriorityByProtocol(String protocolName)1271 public Optional<UwbSession> getSessionWithLowestPriorityByProtocol(String protocolName) { 1272 return mSessionTable.values().stream().filter( 1273 s -> s.mProtocolName.equals(protocolName)).min( 1274 Comparator.comparingInt(UwbSession::getStackSessionPriority)); 1275 } 1276 getSessionIdSet()1277 public Set<Integer> getSessionIdSet() { 1278 return mSessionTable.values() 1279 .stream() 1280 .map(v -> v.getSessionId()) 1281 .collect(Collectors.toSet()); 1282 } 1283 suspendRangingPreconditionCheck(UwbSession uwbSession)1284 private boolean suspendRangingPreconditionCheck(UwbSession uwbSession) { 1285 FiraOpenSessionParams firaOpenSessionParams = 1286 (FiraOpenSessionParams) uwbSession.getParams(); 1287 int deviceType = firaOpenSessionParams.getDeviceType(); 1288 int scheduleMode = firaOpenSessionParams.getScheduledMode(); 1289 int sessionState = uwbSession.getSessionState(); 1290 if (deviceType != FiraParams.RANGING_DEVICE_TYPE_CONTROLLER || 1291 scheduleMode != FiraParams.TIME_SCHEDULED_RANGING || 1292 sessionState != UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 1293 Log.e(TAG, "suspendRangingPreconditionCheck failed - deviceType: " + deviceType + 1294 " scheduleMode: " + scheduleMode + " sessionState: " + sessionState); 1295 return false; 1296 } 1297 return true; 1298 } 1299 sessionUpdateMulticastListCmdPreconditioncheck(UwbSession uwbSession, int action, byte[] subSessionKeyList)1300 private boolean sessionUpdateMulticastListCmdPreconditioncheck(UwbSession uwbSession, 1301 int action, byte[] subSessionKeyList) { 1302 FiraOpenSessionParams firaOpenSessionParams = 1303 (FiraOpenSessionParams) uwbSession.getParams(); 1304 int deviceType = firaOpenSessionParams.getDeviceType(); 1305 int stsConfig = firaOpenSessionParams.getStsConfig(); 1306 byte[] sessionKey = firaOpenSessionParams.getSessionKey(); 1307 Log.i(TAG, "sessionUpdateMulticastListCmdPreconditioncheck - deviceType: " 1308 + deviceType + " stsConfig: " + stsConfig + " action: " + action); 1309 if (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) { 1310 switch (action) { 1311 case FiraParams.MULTICAST_LIST_UPDATE_ACTION_ADD: 1312 case FiraParams.MULTICAST_LIST_UPDATE_ACTION_DELETE: 1313 if (subSessionKeyList != null) { 1314 return false; 1315 } 1316 break; 1317 case FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE: 1318 case FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_32_BYTE: 1319 if (stsConfig 1320 != FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) { 1321 return false; 1322 } 1323 // sessionKey is provided while opening the session and subSessionKeyList 1324 // is provided while updating the multicast list. Check that both the 1325 // sessionKey and subSessionKeyList are either set or not set (as both 1326 // have to be provided by the same source - Host or SE). 1327 if ((sessionKey == null && subSessionKeyList != null) 1328 || (sessionKey != null && subSessionKeyList == null)) { 1329 return false; 1330 } 1331 break; 1332 default: 1333 break; 1334 } 1335 } else { 1336 return false; 1337 } 1338 return true; 1339 } 1340 reconfigureInternal(SessionHandle sessionHandle, @Nullable Params params, Reconfiguration.Reason reason)1341 private synchronized int reconfigureInternal(SessionHandle sessionHandle, 1342 @Nullable Params params, Reconfiguration.Reason reason) { 1343 int status = UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST; 1344 if (!isExistedSession(sessionHandle)) { 1345 Log.i(TAG, "Not initialized session ID"); 1346 return status; 1347 } 1348 int sessionId = getSessionId(sessionHandle); 1349 Log.i(TAG, "reconfigure() - Session ID : " + sessionId); 1350 UwbSession uwbSession = getUwbSession(sessionId); 1351 if (uwbSession.getProtocolName().equals(FiraParams.PROTOCOL_NAME) 1352 && params instanceof FiraRangingReconfigureParams) { 1353 FiraRangingReconfigureParams rangingReconfigureParams = 1354 (FiraRangingReconfigureParams) params; 1355 Log.i(TAG, "reconfigure() - update reconfigure params: " 1356 + rangingReconfigureParams); 1357 // suspendRangingPreconditionCheck only on suspend ranging reconfigure 1358 if ((rangingReconfigureParams.getSuspendRangingRounds() != null) && 1359 (!suspendRangingPreconditionCheck(uwbSession))) { 1360 return UwbUciConstants.STATUS_CODE_REJECTED; 1361 } 1362 if ((rangingReconfigureParams.getAddressList() != null) 1363 && (!sessionUpdateMulticastListCmdPreconditioncheck(uwbSession, 1364 rangingReconfigureParams.getAction(), 1365 rangingReconfigureParams.getSubSessionKeyList()))) { 1366 mSessionNotificationManager.onRangingReconfigureFailed( 1367 uwbSession, UwbUciConstants.STATUS_CODE_INVALID_PARAM); 1368 return UwbUciConstants.STATUS_CODE_REJECTED; 1369 } 1370 // Do not update mParams if this was triggered by framework. 1371 if (reason != Reconfiguration.Reason.FG_STATE_CHANGE) { 1372 uwbSession.updateFiraParamsOnReconfigure(rangingReconfigureParams); 1373 } 1374 } else if (uwbSession.getProtocolName().equals(CccParams.PROTOCOL_NAME) 1375 && params instanceof CccRangingReconfiguredParams) { 1376 CccRangingReconfiguredParams rangingReconfigureParams = 1377 (CccRangingReconfiguredParams) params; 1378 // Do not update mParams if this was triggered by framework. 1379 if (reason != Reconfiguration.Reason.FG_STATE_CHANGE) { 1380 uwbSession.updateCccParamsOnReconfigure(rangingReconfigureParams); 1381 } 1382 } 1383 mEventTask.execute(SESSION_RECONFIG_RANGING, 1384 new Reconfiguration(uwbSession, params, reason)); 1385 return 0; 1386 } 1387 reconfigure(SessionHandle sessionHandle, @Nullable Params params)1388 public synchronized int reconfigure(SessionHandle sessionHandle, @Nullable Params params) { 1389 return reconfigureInternal(sessionHandle, params, Reconfiguration.Reason.REQUESTED_BY_API); 1390 } 1391 1392 /** Send the payload data to a remote device in the UWB session */ sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress, PersistableBundle params, byte[] data)1393 public synchronized void sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress, 1394 PersistableBundle params, byte[] data) { 1395 SendDataInfo info = new SendDataInfo(); 1396 info.sessionHandle = sessionHandle; 1397 info.remoteDeviceAddress = remoteDeviceAddress; 1398 info.params = params; 1399 info.data = data; 1400 1401 mEventTask.execute(SESSION_SEND_DATA, info); 1402 } 1403 1404 /** 1405 * Sets the hybrid UWB controller configuration. 1406 * 1407 * @param sessionHandle : Primary session handle. 1408 * @param params : protocol specific parameters to configure the hybrid 1409 * session controller. 1410 */ setHybridSessionControllerConfiguration(SessionHandle sessionHandle, PersistableBundle params)1411 public void setHybridSessionControllerConfiguration(SessionHandle sessionHandle, 1412 PersistableBundle params) { 1413 1414 if (!isExistedSession(sessionHandle)) { 1415 throw new IllegalStateException("Not initialized session ID: " 1416 + getSessionId(sessionHandle)); 1417 } 1418 1419 HybridSessionConfig hybridSessionConfig = new HybridSessionConfig(); 1420 hybridSessionConfig.sessionHandle = sessionHandle; 1421 hybridSessionConfig.params = params; 1422 1423 mEventTask.execute(SESSION_SET_HUS_CONTROLLER_CONFIG, hybridSessionConfig); 1424 } 1425 1426 /** 1427 * Sets the hybrid UWB controlee configuration. 1428 * 1429 * @param sessionHandle : Primary session handle. 1430 * @param params : protocol specific parameters to configure the hybrid 1431 * session controlee. 1432 */ setHybridSessionControleeConfiguration(SessionHandle sessionHandle, PersistableBundle params)1433 public void setHybridSessionControleeConfiguration(SessionHandle sessionHandle, 1434 PersistableBundle params) { 1435 if (!isExistedSession(sessionHandle)) { 1436 throw new IllegalStateException("Not initialized session ID: " 1437 + getSessionId(sessionHandle)); 1438 } 1439 1440 HybridSessionConfig hybridSessionConfig = new HybridSessionConfig(); 1441 hybridSessionConfig.sessionHandle = sessionHandle; 1442 hybridSessionConfig.params = params; 1443 1444 mEventTask.execute(SESSION_SET_HUS_CONTROLEE_CONFIG, hybridSessionConfig); 1445 } 1446 1447 /** 1448 * Sets the data transfer session configuration 1449 * 1450 * @param sessionHandle : session handle 1451 * @param params : protocol specific parameters to configure data transfer session 1452 */ setDataTransferPhaseConfig(SessionHandle sessionHandle, PersistableBundle params)1453 public void setDataTransferPhaseConfig(SessionHandle sessionHandle, PersistableBundle params) { 1454 if (!isExistedSession(sessionHandle)) { 1455 throw new IllegalStateException("Not initialized session ID: " 1456 + getSessionId(sessionHandle)); 1457 } 1458 1459 UpdateSessionInfo updateSessionInfo = new UpdateSessionInfo(); 1460 updateSessionInfo.sessionHandle = sessionHandle; 1461 updateSessionInfo.params = params; 1462 1463 mEventTask.execute(SESSION_DATA_TRANSFER_PHASE_CONFIG, updateSessionInfo); 1464 } 1465 1466 private static final class SendDataInfo { 1467 public SessionHandle sessionHandle; 1468 public UwbAddress remoteDeviceAddress; 1469 public PersistableBundle params; 1470 public byte[] data; 1471 } 1472 1473 private static final class RangingRoundsUpdateDtTagInfo { 1474 public SessionHandle sessionHandle; 1475 public PersistableBundle params; 1476 } 1477 1478 private static final class UpdateSessionInfo { 1479 public SessionHandle sessionHandle; 1480 public PersistableBundle params; 1481 } 1482 1483 private static final class HybridSessionConfig { 1484 public SessionHandle sessionHandle; 1485 public PersistableBundle params; 1486 } 1487 1488 /** DT Tag ranging round update */ rangingRoundsUpdateDtTag(SessionHandle sessionHandle, PersistableBundle bundle)1489 public void rangingRoundsUpdateDtTag(SessionHandle sessionHandle, 1490 PersistableBundle bundle) { 1491 RangingRoundsUpdateDtTagInfo info = new RangingRoundsUpdateDtTagInfo(); 1492 info.sessionHandle = sessionHandle; 1493 info.params = bundle; 1494 1495 mEventTask.execute(SESSION_UPDATE_DT_TAG_RANGING_ROUNDS, info); 1496 } 1497 1498 /** Query Max Application data size for the given UWB Session */ queryMaxDataSizeBytes(SessionHandle sessionHandle)1499 public synchronized int queryMaxDataSizeBytes(SessionHandle sessionHandle) { 1500 if (!isExistedSession(sessionHandle)) { 1501 throw new IllegalStateException("Not initialized session ID"); 1502 } 1503 1504 int sessionId = getSessionId(sessionHandle); 1505 UwbSession uwbSession = getUwbSession(sessionId); 1506 if (uwbSession == null) { 1507 throw new IllegalStateException("UwbSession not found"); 1508 } 1509 1510 synchronized (uwbSession.getWaitObj()) { 1511 return mNativeUwbManager.queryMaxDataSizeBytes(uwbSession.getSessionId(), 1512 uwbSession.getChipId()); 1513 } 1514 } 1515 1516 /** Handle ranging rounds update for DT Tag */ handleRangingRoundsUpdateDtTag(RangingRoundsUpdateDtTagInfo info)1517 private void handleRangingRoundsUpdateDtTag(RangingRoundsUpdateDtTagInfo info) { 1518 SessionHandle sessionHandle = info.sessionHandle; 1519 Integer sessionId = getSessionId(sessionHandle); 1520 if (sessionId == null) { 1521 Log.i(TAG, "UwbSessionId not found"); 1522 return; 1523 } 1524 UwbSession uwbSession = getUwbSession(sessionId); 1525 if (uwbSession == null) { 1526 Log.i(TAG, "UwbSession not found"); 1527 return; 1528 } 1529 DlTDoARangingRoundsUpdate dlTDoARangingRoundsUpdate = DlTDoARangingRoundsUpdate 1530 .fromBundle(info.params); 1531 1532 if (dlTDoARangingRoundsUpdate.getSessionId() != getSessionId(sessionHandle)) { 1533 throw new IllegalArgumentException("Wrong session ID"); 1534 } 1535 1536 FutureTask<DtTagUpdateRangingRoundsStatus> rangingRoundsUpdateTask = new FutureTask<>( 1537 () -> { 1538 synchronized (uwbSession.getWaitObj()) { 1539 return mNativeUwbManager.sessionUpdateDtTagRangingRounds( 1540 (int) dlTDoARangingRoundsUpdate.getSessionId(), 1541 dlTDoARangingRoundsUpdate.getNoOfRangingRounds(), 1542 dlTDoARangingRoundsUpdate.getRangingRoundIndexes(), 1543 uwbSession.getChipId()); 1544 } 1545 } 1546 ); 1547 1548 DtTagUpdateRangingRoundsStatus status = null; 1549 ExecutorService executor = Executors.newSingleThreadExecutor(); 1550 executor.submit(rangingRoundsUpdateTask); 1551 try { 1552 status = rangingRoundsUpdateTask.get(IUwbAdapter 1553 .RANGING_ROUNDS_UPDATE_DT_TAG_THRESHOLD_MS, TimeUnit.MILLISECONDS); 1554 } catch (TimeoutException e) { 1555 Log.i(TAG, "Failed to update ranging rounds for Dt tag - status : TIMEOUT"); 1556 executor.shutdownNow(); 1557 } catch (InterruptedException | ExecutionException e) { 1558 e.printStackTrace(); 1559 } 1560 // Native stack returns null if unsuccessful 1561 if (status == null) { 1562 status = new DtTagUpdateRangingRoundsStatus( 1563 UwbUciConstants.STATUS_CODE_ERROR_ROUND_INDEX_NOT_ACTIVATED, 1564 0, 1565 new byte[]{}); 1566 } 1567 PersistableBundle params = new DlTDoARangingRoundsUpdateStatus.Builder() 1568 .setStatus(status.getStatus()) 1569 .setNoOfRangingRounds(status.getNoOfRangingRounds()) 1570 .setRangingRoundIndexes(status.getRangingRoundIndexes()) 1571 .build() 1572 .toBundle(); 1573 mSessionNotificationManager.onRangingRoundsUpdateStatus(uwbSession, params); 1574 } 1575 handleSetHybridSessionControllerConfiguration(HybridSessionConfig info)1576 private void handleSetHybridSessionControllerConfiguration(HybridSessionConfig info) { 1577 SessionHandle sessionHandle = info.sessionHandle; 1578 if (!isExistedSession(sessionHandle)) { 1579 Log.e(TAG, "handleSetHybridSessionControllerConfiguration() - cannot find session"); 1580 return; 1581 } 1582 1583 int sessionId = getSessionId(sessionHandle); 1584 UwbSession uwbSession = getUwbSession(sessionId); 1585 1586 // precondition check 1587 int deviceType = uwbSession.getDeviceType(); 1588 int scheduleMode = uwbSession.getScheduledMode(); 1589 int sessionType = uwbSession.getSessionType(); 1590 if (UwbUciConstants.DEVICE_TYPE_CONTROLLER != deviceType 1591 || UwbUciConstants.HYBRID_SCHEDULED_RANGING != scheduleMode 1592 || UwbUciConstants.SESSION_TYPE_HUS_PRIMARY_SESSION != sessionType) { 1593 Log.e(TAG, "SetHybridSessionControllerConfiguration() failed: device type: " 1594 + deviceType + " schedule mode: " 1595 + scheduleMode + " sessionType: " + sessionType); 1596 mSessionNotificationManager.onHybridSessionControllerConfigurationFailed( 1597 uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 1598 return; 1599 } 1600 1601 FiraHybridSessionControllerConfig husConfig = 1602 FiraHybridSessionControllerConfig.fromBundle(info.params); 1603 int numberOfPhases = husConfig.getNumberOfPhases(); 1604 1605 Log.i(TAG, "handleSetHybridSessionControllerConfiguration() - sessionId: " + sessionId 1606 + ", sessionHandle: " + sessionHandle 1607 + ", numberOfPhases: " + numberOfPhases); 1608 1609 ByteBuffer buffer = ByteBuffer.allocate(numberOfPhases 1610 * UWB_HUS_CONTROLLER_PHASE_LIST_EXTENDED_MAC_ADDRESS_SIZE); 1611 buffer.order(ByteOrder.LITTLE_ENDIAN); 1612 1613 for (FiraHybridSessionControllerConfig.FiraHybridSessionPhaseList phaseList : 1614 husConfig.getPhaseList()) { 1615 buffer.putInt(phaseList.getSessionId()); 1616 buffer.putShort(phaseList.getStartSlotIndex()); 1617 buffer.putShort(phaseList.getEndSlotIndex()); 1618 1619 byte messageControl = phaseList.getMessageControl(); 1620 buffer.put(messageControl); 1621 1622 // validate the MacAddress 1623 byte macAddressMode = (byte) (messageControl & 0x01); 1624 int addressByteLength = (macAddressMode 1625 == UwbUciConstants.SHORT_MAC_ADDRESS) 1626 ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH 1627 : UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH; 1628 UwbAddress uwbAddress = phaseList.getMacAddress(); 1629 if (uwbAddress == null || uwbAddress.size() != addressByteLength) { 1630 Log.e(TAG, "handleSetHybridSessionControllerConfiguration() invalid UWB address"); 1631 mSessionNotificationManager.onHybridSessionControllerConfigurationFailed( 1632 uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 1633 return; 1634 } 1635 1636 buffer.put(getComputedMacAddress(uwbAddress)); 1637 } 1638 1639 byte[] phaseListArray = Arrays.copyOf(buffer.array(), buffer.position()); 1640 // create session set hus controller configuration task 1641 FutureTask<Integer> sessionsetHybridControllerConfigTask = new FutureTask<>( 1642 (Callable<Integer>) () -> { 1643 int status = UwbUciConstants.STATUS_CODE_FAILED; 1644 synchronized (uwbSession.getWaitObj()) { 1645 status = mNativeUwbManager.setHybridSessionControllerConfiguration( 1646 sessionId, numberOfPhases, phaseListArray, 1647 uwbSession.getChipId()); 1648 } 1649 return status; 1650 } 1651 ); 1652 1653 // execute task 1654 int status = UwbUciConstants.STATUS_CODE_FAILED; 1655 try { 1656 status = mUwbInjector.runTaskOnSingleThreadExecutor( 1657 sessionsetHybridControllerConfigTask, 1658 IUwbAdapter.SESSION_CONFIGURATION_THRESHOLD_MS); 1659 } catch (TimeoutException e) { 1660 Log.e(TAG, "Failed to set session hybrid controller config : TIMEOUT"); 1661 mSessionNotificationManager.onHybridSessionControllerConfigurationFailed( 1662 uwbSession, status); 1663 } catch (InterruptedException | ExecutionException e) { 1664 Log.e(TAG, "Exception while executing task " + e); 1665 } 1666 1667 if (UwbUciConstants.STATUS_CODE_OK == status) { 1668 mSessionNotificationManager.onHybridSessionControllerConfigured(uwbSession, 1669 status); 1670 } else { 1671 Log.e(TAG, "Failed to configure controller hybrid session - status : " + status); 1672 mSessionNotificationManager.onHybridSessionControllerConfigurationFailed(uwbSession, 1673 status); 1674 } 1675 } 1676 handleSetHybridSessionControleeConfiguration(HybridSessionConfig info)1677 private void handleSetHybridSessionControleeConfiguration(HybridSessionConfig info) { 1678 SessionHandle sessionHandle = info.sessionHandle; 1679 if (!isExistedSession(sessionHandle)) { 1680 Log.e(TAG, "handleSetHybridSessionControlleeConfiguration() - cannot find session"); 1681 return; 1682 } 1683 1684 int sessionId = getSessionId(sessionHandle); 1685 UwbSession uwbSession = getUwbSession(sessionId); 1686 1687 // precondition check 1688 int deviceType = uwbSession.getDeviceType(); 1689 int scheduleMode = uwbSession.getScheduledMode(); 1690 int sessionType = uwbSession.getSessionType(); 1691 if (UwbUciConstants.DEVICE_TYPE_CONTROLEE != deviceType 1692 || UwbUciConstants.HYBRID_SCHEDULED_RANGING != scheduleMode 1693 || UwbUciConstants.SESSION_TYPE_HUS_PRIMARY_SESSION != sessionType) { 1694 Log.e(TAG, "handleSetHybridSessionControleeConfiguration() failed: device type: " 1695 + deviceType + " schedule mode: " + scheduleMode 1696 + " sessionType: " + sessionType); 1697 mSessionNotificationManager.onHybridSessionControleeConfigurationFailed( 1698 uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 1699 return; 1700 } 1701 1702 FiraHybridSessionControleeConfig controleeConfig = 1703 FiraHybridSessionControleeConfig.fromBundle(info.params); 1704 int numberOfPhases = controleeConfig.getNumberOfPhases(); 1705 1706 Log.i(TAG, "handleSetHybridSessionControleeConfiguration() - sessionId: " + sessionId 1707 + ", sessionHandle: " + sessionHandle 1708 + ", numberOfPhases: " + numberOfPhases); 1709 1710 ByteBuffer phaseListBuffer = ByteBuffer.allocate(numberOfPhases 1711 * UWB_HUS_CONTROLEE_PHASE_LIST_SIZE); 1712 phaseListBuffer.order(ByteOrder.LITTLE_ENDIAN); 1713 1714 for (FiraHybridSessionControleeConfig.FiraHybridSessionPhaseList phaseList : 1715 controleeConfig.getPhaseList()) { 1716 phaseListBuffer.putInt(mNativeUwbManager.getSessionToken(phaseList.getSessionHandle(), 1717 uwbSession.getChipId())); 1718 } 1719 1720 // create session set hus controlee configuration task 1721 FutureTask<Integer> sessionsetHybridControleeConfigTask = new FutureTask<>( 1722 (Callable<Integer>) () -> { 1723 int status = UwbUciConstants.STATUS_CODE_FAILED; 1724 synchronized (uwbSession.getWaitObj()) { 1725 status = mNativeUwbManager.setHybridSessionControleeConfiguration( 1726 sessionId, numberOfPhases, 1727 phaseListBuffer.array(), 1728 uwbSession.getChipId()); 1729 } 1730 return status; 1731 } 1732 ); 1733 1734 // execute task 1735 int status = UwbUciConstants.STATUS_CODE_FAILED; 1736 try { 1737 status = mUwbInjector.runTaskOnSingleThreadExecutor( 1738 sessionsetHybridControleeConfigTask, 1739 IUwbAdapter.SESSION_CONFIGURATION_THRESHOLD_MS); 1740 } catch (TimeoutException e) { 1741 Log.e(TAG, "Failed to set session hybrid controlee config : TIMEOUT"); 1742 mSessionNotificationManager.onHybridSessionControleeConfigurationFailed( 1743 uwbSession, status); 1744 } catch (InterruptedException | ExecutionException e) { 1745 Log.e(TAG, "Exception while executing task " + e); 1746 } 1747 1748 if (UwbUciConstants.STATUS_CODE_OK == status) { 1749 mSessionNotificationManager.onHybridSessionControleeConfigured(uwbSession, 1750 status); 1751 } else { 1752 Log.e(TAG, "Failed to configure controlee hybrid session - status : " + status); 1753 mSessionNotificationManager.onHybridSessionControleeConfigurationFailed(uwbSession, 1754 status); 1755 } 1756 } 1757 handleSetDataTransferPhaseConfig(UpdateSessionInfo info)1758 private void handleSetDataTransferPhaseConfig(UpdateSessionInfo info) { 1759 SessionHandle sessionHandle = info.sessionHandle; 1760 Integer sessionId = getSessionId(sessionHandle); 1761 UwbSession uwbSession = getUwbSession(sessionHandle); 1762 1763 int sessionType = uwbSession.getSessionType(); 1764 int deviceType = uwbSession.getDeviceType(); 1765 int sessionState = uwbSession.getSessionState(); 1766 if (UwbUciConstants.DEVICE_TYPE_CONTROLLER != deviceType 1767 || (sessionType != FiraParams.SESSION_TYPE_DATA_TRANSFER 1768 && sessionType != FiraParams.SESSION_TYPE_IN_BAND_DATA_PHASE) 1769 || (sessionState != UwbUciConstants.UWB_SESSION_STATE_IDLE 1770 && sessionState != UwbUciConstants.UWB_SESSION_STATE_ACTIVE)) { 1771 Log.e(TAG, "SetDataTransferPhaseConfig failed: session type:" + sessionType 1772 + " device type:" + deviceType + " sessionState:" + sessionState); 1773 1774 mSessionNotificationManager.onDataTransferPhaseConfigFailed(uwbSession, 1775 UwbUciConstants.STATUS_CODE_REJECTED); 1776 return; 1777 } 1778 1779 FiraDataTransferPhaseConfig dataTransferPhaseConfig = 1780 FiraDataTransferPhaseConfig.fromBundle(info.params); 1781 1782 List<FiraDataTransferPhaseManagementList> mDataTransferPhaseManagementList = 1783 dataTransferPhaseConfig.getDataTransferPhaseManagementList(); 1784 int dataTransferManagementListSize = mDataTransferPhaseManagementList.size(); 1785 int dataTransferControl = dataTransferPhaseConfig.getDataTransferControl(); 1786 int slotBitmapSizeInBytes = 1 << ((dataTransferControl & 0X0F) >> 1); 1787 1788 List<byte[]> macAddressList = new ArrayList<>(); 1789 ByteBuffer slotBitmapByteBuffer = ByteBuffer.allocate(dataTransferManagementListSize 1790 * slotBitmapSizeInBytes); 1791 slotBitmapByteBuffer.order(ByteOrder.LITTLE_ENDIAN); 1792 ByteBuffer stopDataTransferByteBuffer = ByteBuffer.allocate(dataTransferManagementListSize); 1793 1794 int addressByteLength = ((dataTransferControl & 0x01) 1795 == UwbUciConstants.SHORT_MAC_ADDRESS) 1796 ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH : UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH; 1797 1798 for (FiraDataTransferPhaseManagementList dataTransferPhaseManagementList : 1799 mDataTransferPhaseManagementList) { 1800 UwbAddress uwbAddress = dataTransferPhaseManagementList.getUwbAddress(); 1801 byte[] slotBitMap = dataTransferPhaseManagementList.getSlotBitMap(); 1802 byte stopDataTransfer = dataTransferPhaseManagementList.getStopDataTransfer(); 1803 1804 if (uwbAddress != null && uwbAddress.size() == addressByteLength 1805 && slotBitMap.length == slotBitmapSizeInBytes) { 1806 macAddressList.add(getComputedMacAddress(uwbAddress)); 1807 slotBitmapByteBuffer.put(slotBitMap); 1808 stopDataTransferByteBuffer.put(stopDataTransfer); 1809 } else { 1810 Log.e(TAG, "handleSetDataTransferPhaseConfig: slot bitmap size " 1811 + "or address is not matching"); 1812 return; 1813 } 1814 } 1815 1816 // Check for buffer size mismatches 1817 if (slotBitmapByteBuffer.array().length 1818 != (slotBitmapSizeInBytes * dataTransferManagementListSize) 1819 || macAddressList.size() != dataTransferManagementListSize) { 1820 Log.e(TAG, "handleSetDataTransferPhaseConfig: slot bitmap buffer size or address list" 1821 + " size mismatch"); 1822 return; 1823 } 1824 1825 // create session data transfer phase configuration task 1826 FutureTask<Integer> sessionDataTransferPhaseConfigTask = new FutureTask<>( 1827 (Callable<Integer>) () -> { 1828 int status = UwbUciConstants.STATUS_CODE_FAILED; 1829 synchronized (uwbSession.getWaitObj()) { 1830 status = mNativeUwbManager.setDataTransferPhaseConfig(sessionId, 1831 (byte) dataTransferPhaseConfig.getDtpcmRepetition(), 1832 (byte) dataTransferControl, 1833 (byte) dataTransferManagementListSize, 1834 ArrayUtils.toPrimitive(macAddressList), 1835 slotBitmapByteBuffer.array(), 1836 stopDataTransferByteBuffer.array(), 1837 uwbSession.getChipId()); 1838 } 1839 return status; 1840 } 1841 ); 1842 1843 // execute task 1844 int status = UwbUciConstants.STATUS_CODE_FAILED; 1845 try { 1846 status = mUwbInjector.runTaskOnSingleThreadExecutor(sessionDataTransferPhaseConfigTask, 1847 IUwbAdapter.SESSION_DATA_TRANSFER_PHASE_CONFIG_THRESHOLD_MS); 1848 } catch (TimeoutException e) { 1849 Log.e(TAG, "Failed to set session data transfer phase config : TIMEOUT"); 1850 mSessionNotificationManager.onDataTransferPhaseConfigFailed(uwbSession, status); 1851 } catch (InterruptedException | ExecutionException e) { 1852 Log.e(TAG, "Exception while executing task " + e); 1853 } 1854 1855 if (status != UwbUciConstants.STATUS_CODE_OK) { 1856 mSessionNotificationManager.onDataTransferPhaseConfigFailed(uwbSession, status); 1857 } 1858 } 1859 removeSession(UwbSession uwbSession)1860 void removeSession(UwbSession uwbSession) { 1861 if (uwbSession != null) { 1862 try { 1863 uwbSession.getBinder().unlinkToDeath(uwbSession, 0); 1864 } catch (NoSuchElementException e) { 1865 Log.e(TAG, "unlinkToDeath fail - sessionID : " + uwbSession.getSessionId()); 1866 } 1867 removeAdvertiserData(uwbSession); 1868 uwbSession.close(); 1869 removeFromNonPrivilegedUidToFiraSessionTableIfNecessary(uwbSession); 1870 if (!uwbSession.isDataDeliveryPermissionCheckNeeded()) { 1871 mUwbInjector.finishUwbRangingPermissionForDataDelivery( 1872 uwbSession.getAttributionSource()); 1873 } 1874 mSessionTokenMap.remove(uwbSession.getSessionId()); 1875 mSessionTable.remove(uwbSession.getSessionHandle()); 1876 mDbgRecentlyClosedSessions.add(uwbSession); 1877 } 1878 } 1879 removeAdvertiserData(UwbSession uwbSession)1880 private void removeAdvertiserData(UwbSession uwbSession) { 1881 for (long remoteMacAddress : uwbSession.getRemoteMacAddressList()) { 1882 mAdvertiseManager.removeAdvertiseTarget(remoteMacAddress); 1883 } 1884 } 1885 addToNonPrivilegedUidToFiraSessionTableIfNecessary(@onNull UwbSession uwbSession)1886 void addToNonPrivilegedUidToFiraSessionTableIfNecessary(@NonNull UwbSession uwbSession) { 1887 if (uwbSession.getSessionType() != UwbUciConstants.SESSION_TYPE_RANGING) { 1888 return; 1889 } 1890 synchronized (mNonPrivilegedUidToFiraSessionsTable) { 1891 AttributionSource nonPrivilegedAppAttrSource = 1892 uwbSession.getAnyNonPrivilegedAppInAttributionSource(); 1893 if (nonPrivilegedAppAttrSource != null) { 1894 Log.d(TAG, "Detected start of non privileged FIRA session from " 1895 + nonPrivilegedAppAttrSource); 1896 List<UwbSession> sessions = mNonPrivilegedUidToFiraSessionsTable.computeIfAbsent( 1897 nonPrivilegedAppAttrSource.getUid(), v -> new ArrayList<>()); 1898 sessions.add(uwbSession); 1899 } 1900 } 1901 } 1902 removeFromNonPrivilegedUidToFiraSessionTableIfNecessary(@onNull UwbSession uwbSession)1903 void removeFromNonPrivilegedUidToFiraSessionTableIfNecessary(@NonNull UwbSession uwbSession) { 1904 if (uwbSession.getSessionType() != UwbUciConstants.SESSION_TYPE_RANGING) { 1905 return; 1906 } 1907 AttributionSource nonPrivilegedAppAttrSource = 1908 uwbSession.getAnyNonPrivilegedAppInAttributionSource(); 1909 if (nonPrivilegedAppAttrSource == null) { 1910 return; 1911 } 1912 Log.d(TAG, "Detected end of non privileged FIRA session from " 1913 + nonPrivilegedAppAttrSource); 1914 synchronized (mNonPrivilegedUidToFiraSessionsTable) { 1915 List<UwbSession> sessions = mNonPrivilegedUidToFiraSessionsTable.get( 1916 nonPrivilegedAppAttrSource.getUid()); 1917 if (sessions == null) { 1918 Log.wtf(TAG, "No sessions found for uid: " 1919 + nonPrivilegedAppAttrSource.getUid()); 1920 return; 1921 } 1922 sessions.remove(uwbSession); 1923 if (sessions.isEmpty()) { 1924 mNonPrivilegedUidToFiraSessionsTable.remove( 1925 nonPrivilegedAppAttrSource.getUid()); 1926 } 1927 } 1928 } 1929 1930 private static class Reconfiguration { 1931 public final UwbSession mUwbSession; 1932 public final Params mParams; 1933 public final Reason mReason; 1934 1935 /** 1936 * Reason for the reconfiguration. If mParams is an instance of {@link 1937 * FiraRangingReconfigureParams}, the reason can be interpreted as an action-specific 1938 * reason code. 1939 */ 1940 public enum Reason { 1941 UNKNOWN, LOST_CONNECTION, REQUESTED_BY_API, FG_STATE_CHANGE; 1942 1943 /** 1944 * Use this for {@link FiraParams.MULTICAST_LIST_UPDATE_ACTION_DELETE} actions. 1945 * @return the reason for controlee removal. 1946 */ asControleeRemovedReason()1947 public @FiraOnControleeAddRemoveParams.Reason int asControleeRemovedReason() { 1948 switch (this) { 1949 case LOST_CONNECTION: 1950 return FiraOnControleeAddRemoveParams.Reason.LOST_CONNECTION; 1951 case REQUESTED_BY_API: 1952 return FiraOnControleeAddRemoveParams.Reason.REQUESTED_BY_API; 1953 default: 1954 return FiraOnControleeAddRemoveParams.Reason.UNKNOWN; 1955 } 1956 } 1957 } 1958 Reconfiguration(UwbSession uwbSession, Params params, Reason reason)1959 Reconfiguration(UwbSession uwbSession, Params params, Reason reason) { 1960 mUwbSession = uwbSession; 1961 mParams = params; 1962 mReason = reason; 1963 } 1964 1965 } 1966 1967 private class EventTask extends Handler { 1968 EventTask(Looper looper)1969 EventTask(Looper looper) { 1970 super(looper); 1971 } 1972 1973 @Override handleMessage(Message msg)1974 public void handleMessage(Message msg) { 1975 int type = msg.what; 1976 switch (type) { 1977 case SESSION_OPEN_RANGING: { 1978 UwbSession uwbSession = (UwbSession) msg.obj; 1979 handleOpenRanging(uwbSession); 1980 break; 1981 } 1982 1983 case SESSION_START_RANGING: { 1984 UwbSession uwbSession = (UwbSession) msg.obj; 1985 handleStartRanging(uwbSession); 1986 break; 1987 } 1988 1989 case SESSION_STOP_RANGING: { 1990 UwbSession uwbSession = (UwbSession) msg.obj; 1991 boolean triggeredBySystemPolicy = msg.arg1 == 1; 1992 handleStopRanging(uwbSession, triggeredBySystemPolicy); 1993 break; 1994 } 1995 1996 case SESSION_RECONFIG_RANGING: { 1997 Log.d(TAG, "SESSION_RECONFIG_RANGING"); 1998 Reconfiguration reconfiguration = (Reconfiguration) msg.obj; 1999 handleReconfigure(reconfiguration.mUwbSession, reconfiguration.mParams, 2000 reconfiguration.mReason); 2001 break; 2002 } 2003 2004 case SESSION_DEINIT: { 2005 SessionHandle sessionHandle = (SessionHandle) msg.obj; 2006 int reason = msg.arg1; 2007 handleDeInitWithReason(sessionHandle, reason); 2008 break; 2009 } 2010 2011 case SESSION_ON_DEINIT: { 2012 UwbSession uwbSession = (UwbSession) msg.obj; 2013 handleOnDeInit(uwbSession); 2014 break; 2015 } 2016 2017 case SESSION_SEND_DATA: { 2018 Log.d(TAG, "SESSION_SEND_DATA"); 2019 SendDataInfo info = (SendDataInfo) msg.obj; 2020 handleSendData(info); 2021 break; 2022 } 2023 2024 case SESSION_UPDATE_DT_TAG_RANGING_ROUNDS: { 2025 Log.d(TAG, "SESSION_UPDATE_DT_TAG_RANGING_ROUNDS"); 2026 RangingRoundsUpdateDtTagInfo info = (RangingRoundsUpdateDtTagInfo) msg.obj; 2027 handleRangingRoundsUpdateDtTag(info); 2028 break; 2029 } 2030 2031 case SESSION_SET_HUS_CONTROLLER_CONFIG: { 2032 Log.d(TAG, "SESSION_SET_HUS_CONTROLLER_CONFIG"); 2033 HybridSessionConfig info = (HybridSessionConfig) msg.obj; 2034 handleSetHybridSessionControllerConfiguration(info); 2035 break; 2036 } 2037 2038 case SESSION_SET_HUS_CONTROLEE_CONFIG: { 2039 Log.d(TAG, "SESSION_SET_HUS_CONTROLEE_CONFIG"); 2040 HybridSessionConfig info = (HybridSessionConfig) msg.obj; 2041 handleSetHybridSessionControleeConfiguration(info); 2042 break; 2043 } 2044 2045 case SESSION_DATA_TRANSFER_PHASE_CONFIG: { 2046 Log.d(TAG, "SESSION_DATA_TRANSFER_PHASE_CONFIG"); 2047 UpdateSessionInfo info = (UpdateSessionInfo) msg.obj; 2048 handleSetDataTransferPhaseConfig(info); 2049 break; 2050 } 2051 2052 case SESSION_RF_TEST_CMD: { 2053 Log.d(TAG, "SESSION_RF_TEST_CMD"); 2054 UwbSession uwbSession = (UwbSession) msg.obj; 2055 handleRfTestCommand(uwbSession); 2056 break; 2057 } 2058 2059 case SESSION_STOP_RF_TEST_SESSION: { 2060 Log.d(TAG, "SESSION_STOP_RF_TEST_SESSION"); 2061 UwbSession uwbSession = (UwbSession) msg.obj; 2062 handleStopRfTest(uwbSession); 2063 break; 2064 } 2065 2066 default: { 2067 Log.d(TAG, "EventTask : Undefined Task"); 2068 break; 2069 } 2070 } 2071 } 2072 execute(int task, Object obj)2073 public void execute(int task, Object obj) { 2074 Message msg = mEventTask.obtainMessage(); 2075 msg.what = task; 2076 msg.obj = obj; 2077 this.sendMessage(msg); 2078 } 2079 execute(int task, Object obj, int arg1)2080 public void execute(int task, Object obj, int arg1) { 2081 Message msg = mEventTask.obtainMessage(); 2082 msg.what = task; 2083 msg.obj = obj; 2084 msg.arg1 = arg1; 2085 this.sendMessage(msg); 2086 } 2087 handleOpenRanging(UwbSession uwbSession)2088 private void handleOpenRanging(UwbSession uwbSession) { 2089 Trace.beginSection("UWB#handleOpenRanging"); 2090 // TODO(b/211445008): Consolidate to a single uwb thread. 2091 FutureTask<Integer> initSessionTask = new FutureTask<>( 2092 () -> { 2093 int status = UwbUciConstants.STATUS_CODE_FAILED; 2094 synchronized (uwbSession.getWaitObj()) { 2095 uwbSession.setOperationType(OPERATION_TYPE_INIT_SESSION); 2096 status = mNativeUwbManager.initSession( 2097 uwbSession.getSessionId(), 2098 uwbSession.getSessionType(), 2099 uwbSession.getChipId()); 2100 if (status != UwbUciConstants.STATUS_CODE_OK) { 2101 return status; 2102 } 2103 mSessionTokenMap.put(uwbSession.getSessionId(), mNativeUwbManager 2104 .getSessionToken(uwbSession.getSessionId(), 2105 uwbSession.getChipId())); 2106 uwbSession.getWaitObj().blockingWait(); 2107 status = UwbUciConstants.STATUS_CODE_FAILED; 2108 if (uwbSession.getSessionState() 2109 == UwbUciConstants.UWB_SESSION_STATE_INIT) { 2110 uwbSession.setNeedsQueryUwbsTimestamp( 2111 null /* cccRangingStartParams */); 2112 uwbSession.setAbsoluteInitiationTimeIfNeeded(); 2113 status = UwbSessionManager.this.setAppConfigurations(uwbSession); 2114 uwbSession.resetAbsoluteInitiationTime(); 2115 if (status != UwbUciConstants.STATUS_CODE_OK) { 2116 return status; 2117 } 2118 2119 uwbSession.getWaitObj().blockingWait(); 2120 status = UwbUciConstants.STATUS_CODE_FAILED; 2121 if (uwbSession.getSessionState() 2122 == UwbUciConstants.UWB_SESSION_STATE_IDLE) { 2123 mSessionNotificationManager.onRangingOpened(uwbSession); 2124 status = UwbUciConstants.STATUS_CODE_OK; 2125 } else { 2126 status = UwbUciConstants.STATUS_CODE_FAILED; 2127 } 2128 return status; 2129 } 2130 return status; 2131 } 2132 }); 2133 2134 int status = UwbUciConstants.STATUS_CODE_FAILED; 2135 try { 2136 status = mUwbInjector.runTaskOnSingleThreadExecutor(initSessionTask, 2137 IUwbAdapter.RANGING_SESSION_OPEN_THRESHOLD_MS); 2138 } catch (TimeoutException e) { 2139 Log.i(TAG, "Failed to initialize session - status : TIMEOUT"); 2140 } catch (InterruptedException e) { 2141 e.printStackTrace(); 2142 } catch (ExecutionException e) { 2143 e.printStackTrace(); 2144 } 2145 2146 mUwbMetrics.logRangingInitEvent(uwbSession, status); 2147 if (status != UwbUciConstants.STATUS_CODE_OK) { 2148 Log.i(TAG, "Failed to initialize session - status : " + status); 2149 mSessionNotificationManager.onRangingOpenFailed(uwbSession, status); 2150 uwbSession.setOperationType(SESSION_ON_DEINIT); 2151 mNativeUwbManager.deInitSession(uwbSession.getSessionId(), uwbSession.getChipId()); 2152 removeSession(uwbSession); 2153 } 2154 Log.i(TAG, "sessionInit() : finish - sessionId : " + uwbSession.getSessionId()); 2155 Trace.endSection(); 2156 } 2157 handleStartRanging(UwbSession uwbSession)2158 private void handleStartRanging(UwbSession uwbSession) { 2159 Trace.beginSection("UWB#handleStartRanging"); 2160 // TODO(b/211445008): Consolidate to a single uwb thread. 2161 FutureTask<Integer> startRangingTask = new FutureTask<>( 2162 () -> { 2163 int status = UwbUciConstants.STATUS_CODE_FAILED; 2164 synchronized (uwbSession.getWaitObj()) { 2165 uwbSession.setAbsoluteInitiationTimeIfNeeded(); 2166 if (uwbSession.getNeedsAppConfigUpdate()) { 2167 uwbSession.resetNeedsAppConfigUpdate(); 2168 status = mConfigurationManager.setAppConfigurations( 2169 uwbSession.getSessionId(), 2170 uwbSession.getParams(), uwbSession.getChipId(), 2171 getUwbsFiraProtocolVersion(uwbSession.getChipId())); 2172 uwbSession.resetAbsoluteInitiationTime(); 2173 if (status != UwbUciConstants.STATUS_CODE_OK) { 2174 mSessionNotificationManager.onRangingStartFailed( 2175 uwbSession, status); 2176 return status; 2177 } 2178 } 2179 2180 uwbSession.setOperationType(SESSION_START_RANGING); 2181 status = mNativeUwbManager.startRanging(uwbSession.getSessionId(), 2182 uwbSession.getChipId()); 2183 if (status != UwbUciConstants.STATUS_CODE_OK) { 2184 mSessionNotificationManager.onRangingStartFailed( 2185 uwbSession, status); 2186 return status; 2187 } 2188 uwbSession.getWaitObj().blockingWait(); 2189 if (uwbSession.getSessionState() 2190 == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 2191 // TODO: Ensure |rangingStartedParams| is valid for FIRA sessions 2192 // as well. 2193 Params rangingStartedParams = uwbSession.getParams(); 2194 2195 // For ALIRO sessions, retrieve the app configs 2196 if (uwbSession.getProtocolName().equals( 2197 AliroParams.PROTOCOL_NAME)) { 2198 Pair<Integer, AliroRangingStartedParams> statusAndParams = 2199 mConfigurationManager.getAppConfigurations( 2200 uwbSession.getSessionId(), 2201 AliroParams.PROTOCOL_NAME, 2202 new byte[0], 2203 AliroRangingStartedParams.class, 2204 uwbSession.getChipId(), 2205 AliroParams.PROTOCOL_VERSION_1_0); 2206 if (statusAndParams.first != UwbUciConstants.STATUS_CODE_OK) { 2207 Log.e(TAG, "Failed to get ALIRO ranging started params"); 2208 } 2209 rangingStartedParams = statusAndParams.second; 2210 } 2211 2212 // For CCC sessions, retrieve the app configs 2213 if (uwbSession.getProtocolName().equals(CccParams.PROTOCOL_NAME)) { 2214 Pair<Integer, CccRangingStartedParams> statusAndParams = 2215 mConfigurationManager.getAppConfigurations( 2216 uwbSession.getSessionId(), 2217 CccParams.PROTOCOL_NAME, 2218 new byte[0], 2219 CccRangingStartedParams.class, 2220 uwbSession.getChipId(), 2221 CccParams.PROTOCOL_VERSION_1_0); 2222 if (statusAndParams.first != UwbUciConstants.STATUS_CODE_OK) { 2223 Log.e(TAG, "Failed to get CCC ranging started params"); 2224 } 2225 rangingStartedParams = statusAndParams.second; 2226 } 2227 2228 mSessionNotificationManager.onRangingStarted( 2229 uwbSession, rangingStartedParams); 2230 if (uwbSession.hasNonPrivilegedApp() 2231 && !uwbSession.hasNonPrivilegedFgAppOrService()) { 2232 Log.i(TAG, "Session " + uwbSession.getSessionId() 2233 + " reconfiguring ntf control due to app state change"); 2234 uwbSession.reconfigureFiraSessionOnFgStateChange(); 2235 } 2236 } else { 2237 int reasonCode = uwbSession.getLastSessionStatusNtfReasonCode(); 2238 status = 2239 UwbSessionNotificationHelper.convertUciReasonCodeToUciStatusCode( 2240 reasonCode); 2241 mSessionNotificationManager.onRangingStartFailedWithUciReasonCode( 2242 uwbSession, reasonCode); 2243 } 2244 } 2245 return status; 2246 }); 2247 int status = UwbUciConstants.STATUS_CODE_FAILED; 2248 try { 2249 status = mUwbInjector.runTaskOnSingleThreadExecutor(startRangingTask, 2250 IUwbAdapter.RANGING_SESSION_START_THRESHOLD_MS); 2251 } catch (TimeoutException e) { 2252 Log.i(TAG, "Failed to Start Ranging - status : TIMEOUT"); 2253 mSessionNotificationManager.onRangingStartFailed( 2254 uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 2255 } catch (InterruptedException e) { 2256 e.printStackTrace(); 2257 } catch (ExecutionException e) { 2258 e.printStackTrace(); 2259 } 2260 mUwbMetrics.longRangingStartEvent(uwbSession, status); 2261 Trace.endSection(); 2262 } 2263 handleStopRanging(UwbSession uwbSession, boolean triggeredBySystemPolicy)2264 private void handleStopRanging(UwbSession uwbSession, boolean triggeredBySystemPolicy) { 2265 Trace.beginSection("UWB#handleStopRanging"); 2266 // TODO(b/211445008): Consolidate to a single uwb thread. 2267 FutureTask<Integer> stopRangingTask = new FutureTask<>( 2268 () -> { 2269 int status = UwbUciConstants.STATUS_CODE_FAILED; 2270 synchronized (uwbSession.getWaitObj()) { 2271 uwbSession.setOperationType(SESSION_STOP_RANGING); 2272 status = mNativeUwbManager.stopRanging(uwbSession.getSessionId(), 2273 uwbSession.getChipId()); 2274 if (status != UwbUciConstants.STATUS_CODE_OK) { 2275 if (uwbSession.getSessionState() 2276 == UwbUciConstants.UWB_SESSION_STATE_IDLE) { 2277 handleStopRangingParams(uwbSession, true /*systemPolicy*/); 2278 return UwbUciConstants.STATUS_CODE_OK; 2279 } 2280 mSessionNotificationManager.onRangingStopFailed(uwbSession, status); 2281 return status; 2282 } 2283 uwbSession.getWaitObj().blockingWait(); 2284 if (uwbSession.getSessionState() 2285 == UwbUciConstants.UWB_SESSION_STATE_IDLE) { 2286 handleStopRangingParams(uwbSession, triggeredBySystemPolicy); 2287 } else { 2288 status = UwbUciConstants.STATUS_CODE_FAILED; 2289 mSessionNotificationManager.onRangingStopFailed(uwbSession, 2290 status); 2291 } 2292 } 2293 return status; 2294 }); 2295 2296 2297 int status = UwbUciConstants.STATUS_CODE_FAILED; 2298 int timeoutMs = IUwbAdapter.RANGING_SESSION_START_THRESHOLD_MS; 2299 if (uwbSession.getProtocolName().equals(PROTOCOL_NAME)) { 2300 int minTimeoutNecessary = uwbSession.getCurrentFiraRangingIntervalMs() * 4; 2301 timeoutMs = timeoutMs > minTimeoutNecessary ? timeoutMs : minTimeoutNecessary; 2302 } 2303 Log.v(TAG, "Stop timeout: " + timeoutMs); 2304 try { 2305 status = mUwbInjector.runTaskOnSingleThreadExecutor(stopRangingTask, timeoutMs); 2306 } catch (TimeoutException e) { 2307 Log.i(TAG, "Failed to Stop Ranging - status : TIMEOUT"); 2308 mSessionNotificationManager.onRangingStopFailed( 2309 uwbSession, UwbUciConstants.STATUS_CODE_FAILED); 2310 } catch (InterruptedException e) { 2311 e.printStackTrace(); 2312 } catch (ExecutionException e) { 2313 e.printStackTrace(); 2314 } 2315 if (status != UwbUciConstants.STATUS_CODE_FAILED) { 2316 mUwbMetrics.longRangingStopEvent(uwbSession); 2317 } 2318 // Reset all UWB session timers when the session is stopped. 2319 uwbSession.stopTimers(); 2320 removeAdvertiserData(uwbSession); 2321 Trace.endSection(); 2322 } 2323 handleStopRangingParams(UwbSession uwbSession, boolean triggeredBySystemPolicy)2324 private void handleStopRangingParams(UwbSession uwbSession, 2325 boolean triggeredBySystemPolicy) { 2326 PersistableBundle rangingStoppedParamsBundle = new PersistableBundle(); 2327 2328 // For ALIRO sessions, retrieve the app configs 2329 if (uwbSession.getProtocolName().equals(AliroParams.PROTOCOL_NAME) 2330 && mUwbInjector.getDeviceConfigFacade() 2331 .isCccRangingStoppedParamsSendEnabled()) { // Use CCC Flag for ALIRO. 2332 Pair<Integer, AliroRangingStoppedParams> statusAndParams = 2333 mConfigurationManager.getAppConfigurations( 2334 uwbSession.getSessionId(), 2335 AliroParams.PROTOCOL_NAME, 2336 new byte[0], 2337 AliroRangingStoppedParams.class, 2338 uwbSession.getChipId(), 2339 AliroParams.PROTOCOL_VERSION_1_0); 2340 if (statusAndParams.first != UwbUciConstants.STATUS_CODE_OK) { 2341 Log.e(TAG, "Failed to get ALIRO ranging stopped params"); 2342 } 2343 rangingStoppedParamsBundle = statusAndParams.second.toBundle(); 2344 } 2345 2346 // For CCC sessions, retrieve the app configs 2347 if (uwbSession.getProtocolName().equals(CccParams.PROTOCOL_NAME) 2348 && mUwbInjector.getDeviceConfigFacade() 2349 .isCccRangingStoppedParamsSendEnabled()) { 2350 Pair<Integer, CccRangingStoppedParams> statusAndParams = 2351 mConfigurationManager.getAppConfigurations( 2352 uwbSession.getSessionId(), 2353 CccParams.PROTOCOL_NAME, 2354 new byte[0], 2355 CccRangingStoppedParams.class, 2356 uwbSession.getChipId(), 2357 CccParams.PROTOCOL_VERSION_1_0); 2358 if (statusAndParams.first != UwbUciConstants.STATUS_CODE_OK) { 2359 Log.e(TAG, "Failed to get CCC ranging stopped params"); 2360 } 2361 rangingStoppedParamsBundle = statusAndParams.second.toBundle(); 2362 } 2363 2364 int apiReasonCode = triggeredBySystemPolicy 2365 ? RangingChangeReason.SYSTEM_POLICY 2366 : RangingChangeReason.LOCAL_API; 2367 mSessionNotificationManager.onRangingStoppedWithApiReasonCode( 2368 uwbSession, apiReasonCode, rangingStoppedParamsBundle); 2369 } 2370 suspendRangingCallbacks(int suspendRangingRounds, int status, UwbSession uwbSession)2371 private void suspendRangingCallbacks(int suspendRangingRounds, int status, 2372 UwbSession uwbSession) { 2373 if (suspendRangingRounds == FiraParams.SUSPEND_RANGING_ENABLED) { 2374 if (status == UwbUciConstants.STATUS_CODE_OK) { 2375 mSessionNotificationManager.onRangingPaused(uwbSession); 2376 } else { 2377 mSessionNotificationManager.onRangingPauseFailed(uwbSession, status); 2378 } 2379 } else if (suspendRangingRounds == FiraParams.SUSPEND_RANGING_DISABLED) { 2380 if (status == UwbUciConstants.STATUS_CODE_OK) { 2381 mSessionNotificationManager.onRangingResumed(uwbSession); 2382 } else { 2383 mSessionNotificationManager.onRangingResumeFailed(uwbSession, status); 2384 } 2385 } 2386 } 2387 updateAddRemoveCallbacks(UwbSession uwbSession, UwbMulticastListUpdateStatus multicastList, Integer action, Reconfiguration.Reason reason)2388 private int updateAddRemoveCallbacks(UwbSession uwbSession, 2389 UwbMulticastListUpdateStatus multicastList, Integer action, 2390 Reconfiguration.Reason reason) { 2391 int actionStatus = UwbUciConstants.STATUS_CODE_OK; 2392 for (int i = 0; i < multicastList.getNumOfControlee(); i++) { 2393 actionStatus = multicastList.getStatus()[i]; 2394 final UwbAddress address = multicastList.getControleeUwbAddresses()[i]; 2395 if (actionStatus == UwbUciConstants.STATUS_CODE_OK) { 2396 if (isMulticastActionAdd(action)) { 2397 uwbSession.addControlee(address); 2398 mSessionNotificationManager.onControleeAdded( 2399 uwbSession, address); 2400 } else if (action == MULTICAST_LIST_UPDATE_ACTION_DELETE) { 2401 uwbSession.removeControlee(address); 2402 mSessionNotificationManager.onControleeRemoved(uwbSession, address, 2403 reason.asControleeRemovedReason()); 2404 } 2405 } else { 2406 if (isMulticastActionAdd(action)) { 2407 mSessionNotificationManager.onControleeAddFailed( 2408 uwbSession, address, actionStatus); 2409 } else if (action == MULTICAST_LIST_UPDATE_ACTION_DELETE) { 2410 mSessionNotificationManager.onControleeRemoveFailed( 2411 uwbSession, address, 2412 actionStatus, reason.asControleeRemovedReason()); 2413 } 2414 } 2415 } 2416 return actionStatus; 2417 } 2418 handleReconfigure(UwbSession uwbSession, @Nullable Params param, Reconfiguration.Reason reason)2419 private void handleReconfigure(UwbSession uwbSession, @Nullable Params param, 2420 Reconfiguration.Reason reason) { 2421 if (!(param instanceof FiraRangingReconfigureParams 2422 || param instanceof CccRangingReconfiguredParams)) { 2423 Log.e(TAG, "Invalid reconfigure params: " + param); 2424 mSessionNotificationManager.onRangingReconfigureFailed( 2425 uwbSession, UwbUciConstants.STATUS_CODE_INVALID_PARAM); 2426 return; 2427 } 2428 Trace.beginSection("UWB#handleReconfigure"); 2429 2430 final FiraRangingReconfigureParams rangingReconfigureParams = 2431 (param instanceof FiraRangingReconfigureParams) 2432 ? (FiraRangingReconfigureParams) param : null; 2433 // TODO(b/211445008): Consolidate to a single uwb thread. 2434 FutureTask<Integer> cmdTask = new FutureTask<>( 2435 () -> { 2436 int status = UwbUciConstants.STATUS_CODE_FAILED; 2437 int ntfStatus = UwbUciConstants.STATUS_CODE_OK; 2438 synchronized (uwbSession.getWaitObj()) { 2439 // Handle SESSION_UPDATE_CONTROLLER_MULTICAST_LIST_CMD 2440 UwbAddress[] addrList = null; 2441 Integer action = null; 2442 2443 if (rangingReconfigureParams != null) { 2444 addrList = rangingReconfigureParams.getAddressList(); 2445 action = rangingReconfigureParams.getAction(); 2446 } 2447 uwbSession.setOperationType(SESSION_RECONFIG_RANGING); 2448 // Action will indicate if this is a controlee add/remove. 2449 // if null, it's a session configuration change. 2450 if (action != null) { 2451 if (addrList == null) { 2452 Log.e(TAG, 2453 "Multicast update missing the address list."); 2454 return status; 2455 } 2456 int dstAddressListSize = addrList.length; 2457 List<byte[]> dstAddressList = new ArrayList<>(); 2458 for (UwbAddress address : addrList) { 2459 dstAddressList.add(getComputedMacAddress(address)); 2460 } 2461 int[] subSessionIdList; 2462 if (!ArrayUtils.isEmpty( 2463 rangingReconfigureParams.getSubSessionIdList())) { 2464 subSessionIdList = 2465 rangingReconfigureParams.getSubSessionIdList(); 2466 } else { 2467 // Set to 0's for the UCI stack. 2468 subSessionIdList = new int[dstAddressListSize]; 2469 } 2470 boolean isV2 = action 2471 == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE 2472 || action 2473 == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_32_BYTE; 2474 UwbMulticastListUpdateStatus multicastListUpdateStatus = 2475 mNativeUwbManager.controllerMulticastListUpdate( 2476 uwbSession.getSessionId(), 2477 action, 2478 subSessionIdList.length, 2479 ArrayUtils.toPrimitive(dstAddressList), 2480 subSessionIdList, 2481 isV2 ? rangingReconfigureParams 2482 .getSubSessionKeyList() : null, 2483 uwbSession.getChipId()); 2484 status = (multicastListUpdateStatus.getNumOfControlee() == 0) 2485 ? UwbUciConstants.STATUS_CODE_OK : 2486 UwbUciConstants.STATUS_CODE_FAILED; 2487 2488 if (status != UwbUciConstants.STATUS_CODE_OK) { 2489 Log.e(TAG, "Unable to update controller multicast list."); 2490 int i = 0; 2491 UwbAddress[] addresses = 2492 multicastListUpdateStatus.getControleeUwbAddresses(); 2493 for (int st : multicastListUpdateStatus.getStatus()) { 2494 if (st == UwbUciConstants.STATUS_CODE_OK) { 2495 if (isMulticastActionAdd(action)) { 2496 uwbSession.addControlee(addresses[i]); 2497 mSessionNotificationManager.onControleeAdded( 2498 uwbSession, addresses[i]); 2499 } else if (action 2500 == MULTICAST_LIST_UPDATE_ACTION_DELETE) { 2501 uwbSession.removeControlee(addresses[i]); 2502 mSessionNotificationManager.onControleeRemoved( 2503 uwbSession, addresses[i], 2504 reason.asControleeRemovedReason()); 2505 } 2506 } else { 2507 if (isMulticastActionAdd(action)) { 2508 mSessionNotificationManager.onControleeAddFailed( 2509 uwbSession, addresses[i], st); 2510 } else if (action 2511 == MULTICAST_LIST_UPDATE_ACTION_DELETE) { 2512 mSessionNotificationManager.onControleeRemoveFailed( 2513 uwbSession, addresses[i], st, 2514 reason.asControleeRemovedReason()); 2515 } 2516 status = st; 2517 } 2518 i++; 2519 } 2520 if (getUwbsFiraProtocolVersion(uwbSession.getChipId()) 2521 .getMajor() < FIRA_VERSION_MAJOR_2 2522 || (uwbSession.getSessionState() 2523 == UwbUciConstants.UWB_SESSION_STATE_IDLE) 2524 || (multicastListUpdateStatus.getNumOfControlee() 2525 == subSessionIdList.length)) { 2526 return status; 2527 } 2528 } 2529 //Fira 2.0 2530 if (getUwbsFiraProtocolVersion( 2531 uwbSession.getChipId()).getMajor() 2532 >= FIRA_VERSION_MAJOR_2) { 2533 // Action - Add, Status - STATUS_OK 2534 if (isMulticastActionAdd(action)) { 2535 for (UwbAddress address : addrList) { 2536 Log.i(TAG, "address: " + address + " added"); 2537 uwbSession.addControlee(address); 2538 mSessionNotificationManager.onControleeAdded( 2539 uwbSession, address); 2540 } 2541 } else { 2542 if (uwbSession.getSessionState() 2543 == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 2544 //wait for NTF for delete action only 2545 uwbSession.getWaitObj().blockingWait(); 2546 UwbMulticastListUpdateStatus multicastList = 2547 uwbSession.getMulticastListUpdateStatus(); 2548 2549 if (multicastList == null) { 2550 Log.e(TAG, "controller multicast list is empty!"); 2551 return status; 2552 } 2553 ntfStatus = updateAddRemoveCallbacks(uwbSession, 2554 multicastList, action, reason); 2555 } else { 2556 // Action - Delete, State - Idle, Status - STATUS_OK 2557 for (UwbAddress address : addrList) { 2558 Log.i(TAG, "address: " + address + " removed"); 2559 uwbSession.removeControlee(address); 2560 mSessionNotificationManager.onControleeRemoved( 2561 uwbSession, address, 2562 reason.asControleeRemovedReason()); 2563 } 2564 } 2565 } 2566 } else { 2567 //Fira 1.1 2568 uwbSession.getWaitObj().blockingWait(); 2569 2570 UwbMulticastListUpdateStatus multicastList = 2571 uwbSession.getMulticastListUpdateStatus(); 2572 2573 if (multicastList == null) { 2574 Log.e(TAG, "Confirmed controller multicast list is " 2575 + "empty!"); 2576 return status; 2577 } 2578 status = updateAddRemoveCallbacks(uwbSession, multicastList, 2579 action, reason); 2580 } 2581 } else { 2582 // setAppConfigurations only applies to config changes, 2583 // not controlee list changes 2584 status = mConfigurationManager.setAppConfigurations( 2585 uwbSession.getSessionId(), param, uwbSession.getChipId(), 2586 getUwbsFiraProtocolVersion(uwbSession.getChipId())); 2587 // send suspendRangingCallbacks only on suspend ranging 2588 // reconfigure 2589 Integer suspendRangingRounds = rangingReconfigureParams 2590 .getSuspendRangingRounds(); 2591 if (suspendRangingRounds != null) { 2592 suspendRangingCallbacks(suspendRangingRounds, status, 2593 uwbSession); 2594 } 2595 } 2596 if (status == UwbUciConstants.STATUS_CODE_OK 2597 && ntfStatus == UwbUciConstants.STATUS_CODE_OK) { 2598 // only call this if all controlees succeeded otherwise the 2599 // fail status cause a onRangingReconfigureFailed later. 2600 if (reason != Reconfiguration.Reason.FG_STATE_CHANGE) { 2601 mSessionNotificationManager.onRangingReconfigured(uwbSession); 2602 } 2603 } 2604 Log.d(TAG, "Multicast update status: " + status); 2605 return status; 2606 } 2607 }); 2608 int status = UwbUciConstants.STATUS_CODE_FAILED; 2609 try { 2610 status = mUwbInjector.runTaskOnSingleThreadExecutor(cmdTask, 2611 IUwbAdapter.RANGING_SESSION_OPEN_THRESHOLD_MS); 2612 } catch (TimeoutException e) { 2613 Log.i(TAG, "Failed to Reconfigure - status : TIMEOUT"); 2614 } catch (InterruptedException e) { 2615 e.printStackTrace(); 2616 } catch (ExecutionException e) { 2617 e.printStackTrace(); 2618 } 2619 if (status != UwbUciConstants.STATUS_CODE_OK) { 2620 Log.i(TAG, "Failed to Reconfigure : " + status); 2621 if (reason != Reconfiguration.Reason.FG_STATE_CHANGE) { 2622 mSessionNotificationManager.onRangingReconfigureFailed(uwbSession, status); 2623 } 2624 } 2625 Trace.endSection(); 2626 } 2627 isMulticastActionAdd(Integer action)2628 private boolean isMulticastActionAdd(Integer action) { 2629 return action == MULTICAST_LIST_UPDATE_ACTION_ADD 2630 || action == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE 2631 || action == P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_32_BYTE; 2632 } 2633 handleDeInitWithReason(SessionHandle sessionHandle, int reason)2634 private void handleDeInitWithReason(SessionHandle sessionHandle, int reason) { 2635 Trace.beginSection("UWB#handleDeInitWithReason"); 2636 UwbSession uwbSession = getUwbSession(sessionHandle); 2637 if (uwbSession == null) { 2638 Log.w(TAG, "handleDeInitWithReason(): UWB session not found for sessionHandle: " 2639 + sessionHandle); 2640 return; 2641 } 2642 2643 // TODO(b/211445008): Consolidate to a single uwb thread. 2644 FutureTask<Integer> deInitTask = new FutureTask<>( 2645 (Callable<Integer>) () -> { 2646 int status = UwbUciConstants.STATUS_CODE_FAILED; 2647 synchronized (uwbSession.getWaitObj()) { 2648 status = mNativeUwbManager.deInitSession(uwbSession.getSessionId(), 2649 uwbSession.getChipId()); 2650 if (status != UwbUciConstants.STATUS_CODE_OK) { 2651 return status; 2652 } 2653 uwbSession.getWaitObj().blockingWait(); 2654 } 2655 return status; 2656 }); 2657 2658 int status = UwbUciConstants.STATUS_CODE_FAILED; 2659 try { 2660 status = mUwbInjector.runTaskOnSingleThreadExecutor(deInitTask, 2661 IUwbAdapter.RANGING_SESSION_CLOSE_THRESHOLD_MS); 2662 } catch (TimeoutException e) { 2663 Log.i(TAG, "Failed to Stop Ranging - status : TIMEOUT"); 2664 } catch (InterruptedException | ExecutionException e) { 2665 e.printStackTrace(); 2666 } 2667 mUwbMetrics.logRangingCloseEvent(uwbSession, status); 2668 2669 // Reset all UWB session timers when the session is de-initialized (ie, closed). 2670 uwbSession.stopTimers(); 2671 removeSession(uwbSession); 2672 2673 // Notify about Session closure after removing it from the SessionTable. 2674 Log.i(TAG, "onRangingClosed - status : " + status); 2675 mSessionNotificationManager.onRangingClosed(uwbSession, 2676 status == STATUS_CODE_OK ? reason : status); 2677 2678 Log.i(TAG, "deinit finish : status :" + status); 2679 Trace.endSection(); 2680 } 2681 handleSendData(SendDataInfo sendDataInfo)2682 private void handleSendData(SendDataInfo sendDataInfo) { 2683 int status = UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST; 2684 SessionHandle sessionHandle = sendDataInfo.sessionHandle; 2685 if (sessionHandle == null) { 2686 Log.i(TAG, "Not present sessionHandle"); 2687 mSessionNotificationManager.onDataSendFailed( 2688 null, sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params); 2689 return; 2690 } 2691 2692 Integer sessionId = getSessionId(sessionHandle); 2693 if (sessionId == null) { 2694 Log.i(TAG, "UwbSessionId not found"); 2695 mSessionNotificationManager.onDataSendFailed( 2696 null, sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params); 2697 return; 2698 } 2699 2700 // TODO(b/256675656): Check if there is race condition between uwbSession being 2701 // retrieved here and used below (and similar for uwbSession being stored in the 2702 // mLooper message and being used during processing for all other message types). 2703 UwbSession uwbSession = getUwbSession(sessionId); 2704 if (uwbSession == null) { 2705 Log.i(TAG, "UwbSession not found"); 2706 mSessionNotificationManager.onDataSendFailed( 2707 null, sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params); 2708 return; 2709 } 2710 2711 // TODO(b/211445008): Consolidate to a single uwb thread. 2712 FutureTask<Integer> sendDataTask = new FutureTask<>((Callable<Integer>) () -> { 2713 int sendDataStatus = UwbUciConstants.STATUS_CODE_FAILED; 2714 synchronized (uwbSession.getWaitObj()) { 2715 if (!isValidUwbSessionForApplicationDataTransfer(uwbSession)) { 2716 sendDataStatus = UwbUciConstants.STATUS_CODE_FAILED; 2717 Log.i(TAG, "UwbSession not in active state"); 2718 mSessionNotificationManager.onDataSendFailed( 2719 uwbSession, sendDataInfo.remoteDeviceAddress, sendDataStatus, 2720 sendDataInfo.params); 2721 return sendDataStatus; 2722 } 2723 if (!isValidSendDataInfo(sendDataInfo, uwbSession.getChipId())) { 2724 sendDataStatus = UwbUciConstants.STATUS_CODE_INVALID_PARAM; 2725 mSessionNotificationManager.onDataSendFailed( 2726 uwbSession, sendDataInfo.remoteDeviceAddress, sendDataStatus, 2727 sendDataInfo.params); 2728 return sendDataStatus; 2729 } 2730 2731 // Get the UCI sequence number for this data packet, and store it. 2732 short sequenceNum = uwbSession.getAndIncrementDataSndSequenceNumber(); 2733 uwbSession.addSendDataInfo(sequenceNum, sendDataInfo); 2734 2735 sendDataStatus = mNativeUwbManager.sendData( 2736 uwbSession.getSessionId(), 2737 DataTypeConversionUtil.convertShortMacAddressBytesToExtended( 2738 sendDataInfo.remoteDeviceAddress.toBytes()), 2739 sequenceNum, sendDataInfo.data, uwbSession.getChipId()); 2740 mUwbMetrics.logDataTx(uwbSession, sendDataStatus); 2741 if (sendDataStatus != STATUS_CODE_OK) { 2742 Log.e(TAG, "MSG_SESSION_SEND_DATA error status: " + sendDataStatus 2743 + " for data packet sessionId: " + sessionId 2744 + ", sequence number: " + sequenceNum); 2745 mSessionNotificationManager.onDataSendFailed( 2746 uwbSession, sendDataInfo.remoteDeviceAddress, sendDataStatus, 2747 sendDataInfo.params); 2748 uwbSession.removeSendDataInfo(sequenceNum); 2749 } 2750 return sendDataStatus; 2751 } 2752 }); 2753 2754 status = UwbUciConstants.STATUS_CODE_FAILED; 2755 try { 2756 status = mUwbInjector.runTaskOnSingleThreadExecutor(sendDataTask, 2757 IUwbAdapter.RANGING_SESSION_OPEN_THRESHOLD_MS); 2758 } catch (TimeoutException e) { 2759 Log.i(TAG, "Failed to Send data - status : TIMEOUT"); 2760 mSessionNotificationManager.onDataSendFailed(uwbSession, 2761 sendDataInfo.remoteDeviceAddress, status, sendDataInfo.params); 2762 } catch (InterruptedException | ExecutionException e) { 2763 e.printStackTrace(); 2764 } 2765 } 2766 } 2767 isValidUwbSessionForOwrAoaRanging(UwbSession uwbSession)2768 private boolean isValidUwbSessionForOwrAoaRanging(UwbSession uwbSession) { 2769 Params params = uwbSession.getParams(); 2770 if (params instanceof FiraOpenSessionParams) { 2771 FiraOpenSessionParams firaParams = (FiraOpenSessionParams) params; 2772 if (firaParams.getRangingRoundUsage() != ROUND_USAGE_OWR_AOA_MEASUREMENT) { 2773 Log.i(TAG, "OwR Aoa UwbSession: Invalid ranging round usage value = " 2774 + firaParams.getRangingRoundUsage()); 2775 return false; 2776 } 2777 if (firaParams.getDeviceRole() != RANGING_DEVICE_ROLE_OBSERVER) { 2778 Log.i(TAG, "OwR Aoa UwbSession: Invalid device role value = " 2779 + firaParams.getDeviceRole()); 2780 return false; 2781 } 2782 return true; 2783 } 2784 return false; 2785 } 2786 isValidUwbSessionForApplicationDataTransfer(UwbSession uwbSession)2787 private boolean isValidUwbSessionForApplicationDataTransfer(UwbSession uwbSession) { 2788 // The session state must be SESSION_STATE_ACTIVE, as that's required to transmit or receive 2789 // application data. 2790 return uwbSession != null && uwbSession.getSessionState() == UWB_SESSION_STATE_ACTIVE; 2791 } 2792 2793 /** Returns max length of data message possible on a given chip */ getMaxMessageSize(String chipId)2794 private int getMaxMessageSize(String chipId) { 2795 GenericSpecificationParams params = 2796 mUwbInjector.getUwbServiceCore().getCachedSpecificationParams(chipId); 2797 2798 return (params != null && params.getFiraSpecificationParams() != null) 2799 ? params.getFiraSpecificationParams().getMaxMessageSize() 2800 : 0; 2801 } 2802 isValidSendDataInfo(SendDataInfo sendDataInfo, String chipId)2803 private boolean isValidSendDataInfo(SendDataInfo sendDataInfo, String chipId) { 2804 if (sendDataInfo == null || sendDataInfo.data == null 2805 || sendDataInfo.remoteDeviceAddress == null) { 2806 return false; 2807 } 2808 2809 if (sendDataInfo.remoteDeviceAddress.size() 2810 > UwbUciConstants.UWB_DEVICE_EXT_MAC_ADDRESS_LEN) { 2811 return false; 2812 } 2813 2814 final int fixedLength = FiraParams.SESSION_HANDLE_LEN 2815 + UwbUciConstants.UWB_DEVICE_EXT_MAC_ADDRESS_LEN 2816 + FiraParams.SEQUENCE_NUMBER_LENGTH 2817 + FiraParams.DATA_MSG_LENGTH; 2818 2819 int sendDataInfoLength = fixedLength + sendDataInfo.data.length; 2820 int maxMessageSize = getMaxMessageSize(chipId); 2821 if (sendDataInfoLength > maxMessageSize) { 2822 Log.e(TAG, "SendDataInfo length:" + sendDataInfoLength 2823 + " exceeds max supported message size:" + maxMessageSize + " for chipId: " 2824 + chipId); 2825 return false; 2826 } 2827 2828 return true; 2829 } 2830 getUwbsFiraProtocolVersion(String chipId)2831 protected FiraProtocolVersion getUwbsFiraProtocolVersion(String chipId) { 2832 UwbDeviceInfoResponse deviceInfo = 2833 mUwbInjector.getUwbServiceCore().getCachedDeviceInfoResponse(chipId); 2834 if (deviceInfo != null) { 2835 return FiraProtocolVersion.fromLEShort((short) deviceInfo.mUciVersion); 2836 } 2837 2838 // Return a (safe) backward-compatible FiraProtocolVersion if we couldn't retrieve it 2839 // from the UWBS. 2840 return FiraParams.PROTOCOL_VERSION_1_1; 2841 } 2842 2843 /** Represents a UWB session */ 2844 public class UwbSession implements IBinder.DeathRecipient, Closeable { 2845 @VisibleForTesting 2846 public static final long RANGING_RESULT_ERROR_NO_TIMEOUT = 0; 2847 private static final String RANGING_RESULT_ERROR_STREAK_TIMER_TAG = 2848 "UwbSessionRangingResultError"; 2849 private static final long NON_PRIVILEGED_BG_APP_TIMEOUT_MS = 120_000; 2850 @VisibleForTesting 2851 public static final String NON_PRIVILEGED_BG_APP_TIMER_TAG = 2852 "UwbSessionNonPrivilegedBgAppError"; 2853 @VisibleForTesting 2854 static final int ALIRO_SESSION_PRIORITY = 80; 2855 @VisibleForTesting 2856 static final int CCC_SESSION_PRIORITY = 80; 2857 @VisibleForTesting 2858 static final int SYSTEM_APP_SESSION_PRIORITY = 70; 2859 @VisibleForTesting 2860 static final int FG_SESSION_PRIORITY = 60; 2861 // Default session priority value needs to be different from other session priority buckets, 2862 // so we can detect overrides from the shell or System API. 2863 @VisibleForTesting 2864 static final int DEFAULT_SESSION_PRIORITY = 50; 2865 @VisibleForTesting 2866 static final int BG_SESSION_PRIORITY = 40; 2867 2868 private final AttributionSource mAttributionSource; 2869 private final SessionHandle mSessionHandle; 2870 private final int mSessionId; 2871 private final byte mSessionType; 2872 private final int mRangingRoundUsage; 2873 private final IUwbRangingCallbacks mIUwbRangingCallbacks; 2874 private final String mProtocolName; 2875 private final IBinder mIBinder; 2876 private final WaitObj mWaitObj; 2877 private final AttributionSource mNonPrivilegedAppInAttributionSource; 2878 private boolean mAcquiredDefaultPose = false; 2879 private Params mParams; 2880 private int mSessionState; 2881 // Session priority as tracked by the UWB stack that changes based on the requesting 2882 // app/service bg/fg state changes. Note, it will differ from the Fira SESSION_PRIORITY 2883 // param given to UWBS if the state changed after the session became active. 2884 private int mStackSessionPriority; 2885 private boolean mSessionPriorityOverride = false; 2886 private boolean mNeedsAppConfigUpdate = false; 2887 private boolean mNeedsQueryUwbsTimestamp = false; 2888 private UwbMulticastListUpdateStatus mMulticastListUpdateStatus; 2889 private final int mProfileType; 2890 2891 /** 2892 * Keeps track of per-controlee error streak timers for ranging sessions with multiple 2893 * controlees. 2894 */ 2895 @VisibleForTesting 2896 public Map<UwbAddress, AlarmManager.OnAlarmListener> 2897 mMulticastRangingErrorStreakTimerListeners; 2898 /** 2899 * Per-session error streak timer for all session modes except for two-way ranging. 2900 */ 2901 private AlarmManager.OnAlarmListener mRangingResultErrorStreakTimerListener; 2902 private AlarmManager.OnAlarmListener mNonPrivilegedBgAppTimerListener; 2903 private int mOperationType = OPERATION_TYPE_INIT_SESSION; 2904 private final String mChipId; 2905 private boolean mHasNonPrivilegedFgAppOrService = false; 2906 private long mRangingErrorStreakTimeoutMs = RANGING_RESULT_ERROR_NO_TIMEOUT; 2907 // Use a Map<RemoteMacAddress, SortedMap<SequenceNumber, ReceivedDataInfo>> to store all 2908 // the Application payload data packets received in this (active) UWB Session. 2909 // - The outer key (RemoteMacAddress) is used to identify the Advertiser device that sends 2910 // the data (there can be multiple advertisers in the same UWB session). 2911 // - The inner key (SequenceNumber) is used to ensure we don't store duplicate packets, 2912 // and notify them to the higher layers in-order. 2913 // TODO(b/270068278): Change the type of SequenceNumber from Long to Integer everywhere. 2914 private final ConcurrentHashMap<Long, SortedMap<Long, ReceivedDataInfo>> 2915 mReceivedDataInfoMap; 2916 private IPoseSource mPoseSource; 2917 // Application data repetition count 2918 private int mDataRepetitionCount; 2919 // Hybrid session 2920 private int mDeviceType; 2921 private int mScheduleMode; 2922 2923 // Store the UCI sequence number for the next Data packet (to be sent to UWBS). 2924 private short mDataSndSequenceNumber; 2925 // Store a Map<SequenceNumber, SendDataInfo>, for every Data packet (sent to UWBS). It's 2926 // used when the corresponding DataTransferStatusNtf is received (from UWBS). 2927 private final ConcurrentHashMap<Long, SendDataInfo> mSendDataInfoMap; 2928 2929 // Whether data delivery permission check is needed for the ranging session. 2930 private boolean mDataDeliveryPermissionCheckNeeded = true; 2931 2932 // reasonCode from the last received SESSION_STATUS_NTF for this session. 2933 private int mLastSessionStatusNtfReasonCode = -1; 2934 2935 /** 2936 * Acquire to synchronized changes in controlee count 2937 * Guards mControlees and mControleesPendingDisconnection 2938 */ 2939 private final Object mControleeCountLock = new Object(); 2940 2941 /** 2942 * Keeps track of all controlees in the session. 2943 */ 2944 public Map<UwbAddress, UwbControlee> mControlees; 2945 2946 /** Number of controlees pending disconnection due to error streak timeout */ 2947 @GuardedBy("mControleeCountLock") 2948 private final Set<UwbAddress> mControleesPendingDisconnection; 2949 2950 // Keep track of RF Test start session params 2951 private RfTestStartSessionParams mRfTestStartSessionParams = null; 2952 UwbSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId, byte sessionType, String protocolName, Params params, IUwbRangingCallbacks iUwbRangingCallbacks, String chipId)2953 UwbSession(AttributionSource attributionSource, SessionHandle sessionHandle, int sessionId, 2954 byte sessionType, String protocolName, Params params, 2955 IUwbRangingCallbacks iUwbRangingCallbacks, String chipId) { 2956 this.mAttributionSource = attributionSource; 2957 this.mSessionHandle = sessionHandle; 2958 this.mSessionId = sessionId; 2959 this.mSessionType = sessionType; 2960 this.mProtocolName = protocolName; 2961 this.mIUwbRangingCallbacks = iUwbRangingCallbacks; 2962 this.mIBinder = iUwbRangingCallbacks.asBinder(); 2963 this.mSessionState = UwbUciConstants.UWB_SESSION_STATE_DEINIT; 2964 this.mParams = params; 2965 this.mWaitObj = new WaitObj(); 2966 this.mProfileType = convertProtolNameToProfileType(protocolName); 2967 this.mChipId = chipId; 2968 this.mNonPrivilegedAppInAttributionSource = 2969 mUwbInjector.getAnyNonPrivilegedAppInAttributionSource(mAttributionSource); 2970 this.mStackSessionPriority = calculateSessionPriority(); 2971 this.mControlees = new ConcurrentHashMap<>(); 2972 this.mControleesPendingDisconnection = Sets.newConcurrentHashSet(); 2973 2974 if (params instanceof FiraOpenSessionParams) { 2975 FiraOpenSessionParams firaParams = (FiraOpenSessionParams) params; 2976 2977 this.mRangingRoundUsage = firaParams.getRangingRoundUsage(); 2978 2979 // Set up pose sources before we start creating UwbControlees. 2980 switch (firaParams.getFilterType()) { 2981 case FILTER_TYPE_DEFAULT: 2982 this.mPoseSource = mUwbInjector.acquirePoseSource(); 2983 this.mAcquiredDefaultPose = true; 2984 break; 2985 case FILTER_TYPE_APPLICATION: 2986 this.mPoseSource = new ApplicationPoseSource(); 2987 break; 2988 } 2989 2990 if (firaParams.getDestAddressList() != null) { 2991 // Set up list of all controlees involved. 2992 for (UwbAddress address : firaParams.getDestAddressList()) { 2993 mControlees.put(address, 2994 new UwbControlee(address, createFilterEngine(), mUwbInjector)); 2995 } 2996 } 2997 mRangingErrorStreakTimeoutMs = firaParams 2998 .getRangingErrorStreakTimeoutMs(); 2999 3000 // Add stack calculated session priority to Fira open session params. The stack 3001 // session priority might change later based on fg/bg state changes, but the 3002 // SESSION_PRIORITY given to the UWBS on open session will stay the same since 3003 // UWBS doesn't support reconfiguring session priority while the session is active. 3004 // In case the session stops being active, session priority will update on next 3005 // start ranging call. 3006 if (firaParams.getSessionPriority() != DEFAULT_SESSION_PRIORITY) { 3007 mSessionPriorityOverride = true; 3008 mStackSessionPriority = firaParams.getSessionPriority(); 3009 } else { 3010 mParams = firaParams.toBuilder().setSessionPriority( 3011 mStackSessionPriority).build(); 3012 } 3013 this.mDataRepetitionCount = firaParams.getDataRepetitionCount(); 3014 this.mDeviceType = firaParams.getDeviceType(); 3015 this.mScheduleMode = firaParams.getScheduledMode(); 3016 } else { 3017 this.mRangingRoundUsage = -1; 3018 this.mDataRepetitionCount = 0; 3019 this.mDeviceType = -1; 3020 this.mScheduleMode = -1; 3021 } 3022 3023 this.mReceivedDataInfoMap = new ConcurrentHashMap<>(); 3024 this.mDataSndSequenceNumber = 0; 3025 this.mSendDataInfoMap = new ConcurrentHashMap<>(); 3026 this.mMulticastRangingErrorStreakTimerListeners = new ConcurrentHashMap<>(); 3027 } 3028 3029 /** 3030 * Calculates the priority of the session based on the protocol type and the originating 3031 * app/service requesting the session. 3032 * 3033 * Session priority ranking order (from highest to lowest priority): 3034 * 1. Any CCC session 3035 * 2. Any System app/service 3036 * 3. Other apps/services running in Foreground 3037 * 4. Other apps/services running in Background 3038 */ calculateSessionPriority()3039 public int calculateSessionPriority() { 3040 if (mProtocolName.equals(AliroParams.PROTOCOL_NAME)) { 3041 return ALIRO_SESSION_PRIORITY; 3042 } 3043 if (mProtocolName.equals(CccParams.PROTOCOL_NAME)) { 3044 return CCC_SESSION_PRIORITY; 3045 } 3046 if (mNonPrivilegedAppInAttributionSource == null) { 3047 return SYSTEM_APP_SESSION_PRIORITY; 3048 } 3049 boolean isFgAppOrService = mUwbInjector.isForegroundAppOrService( 3050 mNonPrivilegedAppInAttributionSource.getUid(), 3051 mNonPrivilegedAppInAttributionSource.getPackageName()); 3052 if (isFgAppOrService) { 3053 return FG_SESSION_PRIORITY; 3054 } 3055 return BG_SESSION_PRIORITY; 3056 } 3057 3058 /** 3059 * Check the attribution source chain to check if there are any 3p apps. 3060 * @return AttributionSource of first non-system app found in the chain, null otherwise. 3061 */ 3062 @Nullable getAnyNonPrivilegedAppInAttributionSource()3063 public AttributionSource getAnyNonPrivilegedAppInAttributionSource() { 3064 return mNonPrivilegedAppInAttributionSource; 3065 } 3066 3067 /** 3068 * Check the attribution source chain to check if there are any 3p apps. 3069 * @return true if 3p app found in attribution source chain. 3070 */ hasNonPrivilegedApp()3071 public boolean hasNonPrivilegedApp() { 3072 return mNonPrivilegedAppInAttributionSource != null; 3073 } 3074 3075 /** 3076 * Gets the list of controlees active under this session. 3077 */ getControleeList()3078 public List<UwbControlee> getControleeList() { 3079 return new ArrayList<>(mControlees.values()); 3080 } 3081 3082 /** 3083 * Must be public for testing. 3084 * @return The list of controlee addresses that have active ranging error streak timers. 3085 */ getControleesWithOngoingRangingErrorStreak()3086 public List<UwbAddress> getControleesWithOngoingRangingErrorStreak() { 3087 return new ArrayList<>(mMulticastRangingErrorStreakTimerListeners.keySet()); 3088 } 3089 3090 /** 3091 * Store a ReceivedDataInfo for the UwbSession. If we already have stored data from the 3092 * same advertiser and with the same sequence number, this is a no-op. 3093 */ addReceivedDataInfo(ReceivedDataInfo receivedDataInfo)3094 public void addReceivedDataInfo(ReceivedDataInfo receivedDataInfo) { 3095 SortedMap<Long, ReceivedDataInfo> innerMap = mReceivedDataInfoMap.get( 3096 receivedDataInfo.address); 3097 if (innerMap == null) { 3098 innerMap = new TreeMap<>(); 3099 mReceivedDataInfoMap.put(receivedDataInfo.address, innerMap); 3100 } 3101 3102 // Check if the sorted InnerMap has reached the max number of Rx packets we want to 3103 // store; if so we drop the smallest (sequence number) packet between the new received 3104 // packet and the stored packets. 3105 int maxRxPacketsToStore = 3106 mUwbInjector.getDeviceConfigFacade().getRxDataMaxPacketsToStore(); 3107 if (innerMap.size() < maxRxPacketsToStore) { 3108 innerMap.putIfAbsent(receivedDataInfo.sequenceNum, receivedDataInfo); 3109 } else if (innerMap.size() == maxRxPacketsToStore) { 3110 Long smallestStoredSequenceNumber = innerMap.firstKey(); 3111 if (smallestStoredSequenceNumber < receivedDataInfo.sequenceNum 3112 && !innerMap.containsKey(receivedDataInfo.sequenceNum)) { 3113 innerMap.remove(smallestStoredSequenceNumber); 3114 innerMap.putIfAbsent(receivedDataInfo.sequenceNum, receivedDataInfo); 3115 } 3116 } 3117 } 3118 3119 /** 3120 * Return all the ReceivedDataInfo from the given remote device, in sequence number order. 3121 * This method also removes the returned packets from the Map, so the same packet will 3122 * not be returned again (in a future call). 3123 */ getAllReceivedDataInfo(long macAddress)3124 public List<ReceivedDataInfo> getAllReceivedDataInfo(long macAddress) { 3125 SortedMap<Long, ReceivedDataInfo> innerMap = mReceivedDataInfoMap.get(macAddress); 3126 if (innerMap == null) { 3127 // No stored ReceivedDataInfo(s) for the address. 3128 return List.of(); 3129 } 3130 3131 List<ReceivedDataInfo> receivedDataInfoList = new ArrayList<>(innerMap.values()); 3132 innerMap.clear(); 3133 return receivedDataInfoList; 3134 } 3135 clearReceivedDataInfo()3136 private void clearReceivedDataInfo() { 3137 for (long macAddress : getRemoteMacAddressList()) { 3138 SortedMap<Long, ReceivedDataInfo> innerMap = mReceivedDataInfoMap.get(macAddress); 3139 innerMap.clear(); 3140 } 3141 mReceivedDataInfoMap.clear(); 3142 } 3143 3144 /** 3145 * Get (and increment) the UCI sequence number for the next Data packet to be sent to UWBS. 3146 */ getAndIncrementDataSndSequenceNumber()3147 public short getAndIncrementDataSndSequenceNumber() { 3148 return mDataSndSequenceNumber++; 3149 } 3150 3151 /** 3152 * Store a SendDataInfo for a UCI Data packet sent to UWBS. 3153 */ addSendDataInfo(long sequenceNumber, SendDataInfo sendDataInfo)3154 public void addSendDataInfo(long sequenceNumber, SendDataInfo sendDataInfo) { 3155 mSendDataInfoMap.put(sequenceNumber, sendDataInfo); 3156 } 3157 3158 /** 3159 * Remove the SendDataInfo for a UCI packet from the current UWB Session. 3160 */ removeSendDataInfo(long sequenceNumber)3161 public void removeSendDataInfo(long sequenceNumber) { 3162 mSendDataInfoMap.remove(sequenceNumber); 3163 } 3164 3165 /** 3166 * Get the SendDataInfo for a UCI packet from the current UWB Session. 3167 */ 3168 @Nullable getSendDataInfo(long sequenceNumber)3169 public SendDataInfo getSendDataInfo(long sequenceNumber) { 3170 return mSendDataInfoMap.get(sequenceNumber); 3171 } 3172 3173 /** 3174 * Adds a Controlee to the session. This should only be called to reflect 3175 * the state of the native UWB interface. 3176 * @param address The UWB address of the Controlee to add. 3177 */ addControlee(UwbAddress address)3178 public void addControlee(UwbAddress address) { 3179 if (mControlees.containsKey(address)) { 3180 return; 3181 } 3182 synchronized (mControleeCountLock) { 3183 mControlees.put(address, 3184 new UwbControlee(address, createFilterEngine(), mUwbInjector)); 3185 } 3186 } 3187 3188 /** 3189 * Fetches a {@link UwbControlee} object by {@link UwbAddress}. 3190 * @param address The UWB address of the Controlee to find. 3191 * @return The matching {@link UwbControlee}, or null if not found. 3192 */ getControlee(UwbAddress address)3193 public UwbControlee getControlee(UwbAddress address) { 3194 if (mControlees == null || mControlees.isEmpty()) { 3195 Log.d(TAG, "Controlee list is null or empty"); 3196 return null; 3197 } 3198 UwbControlee result = mControlees.get(address); 3199 if (result == null) { 3200 Log.d(TAG, "Failure to find controlee " + address); 3201 } 3202 return result; 3203 } 3204 3205 /** 3206 * Removes a Controlee from the session. This should only be called to reflect 3207 * the state of the native UWB interface. 3208 * @param address The UWB address of the Controlee to remove. 3209 */ removeControlee(UwbAddress address)3210 public void removeControlee(UwbAddress address) { 3211 if (!mControlees.containsKey(address)) { 3212 Log.w(TAG, "Attempted to remove controlee with address " + address 3213 + " that is not in the session."); 3214 return; 3215 } 3216 Log.d(TAG, "Removing controlee."); 3217 stopRangingResultErrorStreakTimerIfSet(address); 3218 mControlees.get(address).close(); 3219 3220 synchronized (mControleeCountLock) { 3221 mControlees.remove(address); 3222 mControleesPendingDisconnection.remove(address); 3223 } 3224 } 3225 getAttributionSource()3226 public AttributionSource getAttributionSource() { 3227 return this.mAttributionSource; 3228 } 3229 getSessionId()3230 public int getSessionId() { 3231 return this.mSessionId; 3232 } 3233 getSessionType()3234 public byte getSessionType() { 3235 return this.mSessionType; 3236 } 3237 getRangingRoundUsage()3238 public int getRangingRoundUsage() { 3239 return this.mRangingRoundUsage; 3240 } 3241 getChipId()3242 public String getChipId() { 3243 return this.mChipId; 3244 } 3245 getSessionHandle()3246 public SessionHandle getSessionHandle() { 3247 return this.mSessionHandle; 3248 } 3249 getParams()3250 public Params getParams() { 3251 return this.mParams; 3252 } 3253 getDataRepetitionCount()3254 public int getDataRepetitionCount() { 3255 return mDataRepetitionCount; 3256 } 3257 getDeviceType()3258 public int getDeviceType() { 3259 return mDeviceType; 3260 } 3261 getScheduledMode()3262 public int getScheduledMode() { 3263 return mScheduleMode; 3264 } 3265 updateAliroParamsOnStart(AliroStartRangingParams rangingStartParams)3266 public void updateAliroParamsOnStart(AliroStartRangingParams rangingStartParams) { 3267 setNeedsQueryUwbsTimestamp(rangingStartParams); 3268 3269 // Need to update the RAN multiplier and initiation time 3270 // from the AliroStartRangingParams for CCC session. 3271 AliroOpenRangingParams newParams = 3272 new AliroOpenRangingParams.Builder((AliroOpenRangingParams) mParams) 3273 .setRanMultiplier(rangingStartParams.getRanMultiplier()) 3274 .setInitiationTimeMs(rangingStartParams.getInitiationTimeMs()) 3275 .setAbsoluteInitiationTimeUs(rangingStartParams 3276 .getAbsoluteInitiationTimeUs()) 3277 .setStsIndex(rangingStartParams.getStsIndex()) 3278 .build(); 3279 this.mParams = newParams; 3280 this.mNeedsAppConfigUpdate = true; 3281 } 3282 updateCccParamsOnStart(CccStartRangingParams rangingStartParams)3283 public void updateCccParamsOnStart(CccStartRangingParams rangingStartParams) { 3284 setNeedsQueryUwbsTimestamp(rangingStartParams); 3285 3286 // Need to update the RAN multiplier and initiation time 3287 // from the CccStartRangingParams for CCC session. 3288 CccOpenRangingParams newParams = 3289 new CccOpenRangingParams.Builder((CccOpenRangingParams) mParams) 3290 .setRanMultiplier(rangingStartParams.getRanMultiplier()) 3291 .setInitiationTimeMs(rangingStartParams.getInitiationTimeMs()) 3292 .setAbsoluteInitiationTimeUs(rangingStartParams 3293 .getAbsoluteInitiationTimeUs()) 3294 .setStsIndex(rangingStartParams.getStsIndex()) 3295 .build(); 3296 this.mParams = newParams; 3297 this.mNeedsAppConfigUpdate = true; 3298 } 3299 3300 /** 3301 * Checks if session priority of the current session changed from the initial value, if so 3302 * updates the session priority param and marks session for needed app config update. 3303 */ updateFiraParamsOnStartIfChanged()3304 public void updateFiraParamsOnStartIfChanged() { 3305 // Need to check if session priority changed and update if it did 3306 FiraOpenSessionParams firaOpenSessionParams = (FiraOpenSessionParams) mParams; 3307 if (mStackSessionPriority != firaOpenSessionParams.getSessionPriority()) { 3308 this.mParams = ((FiraOpenSessionParams) mParams).toBuilder().setSessionPriority( 3309 mStackSessionPriority).build(); 3310 this.mNeedsAppConfigUpdate = true; 3311 } 3312 3313 setNeedsQueryUwbsTimestamp(null /* rangingStartParams */); 3314 } 3315 3316 /** 3317 * Sets {@code mNeedsQueryUwbsTimestamp} to {@code true}, if the UWBS Timestamp needs to be 3318 * fetched from the UWBS controller (for computing an absolute UWB initiation time). 3319 */ setNeedsQueryUwbsTimestamp(@ullable Params startRangingParams)3320 public void setNeedsQueryUwbsTimestamp(@Nullable Params startRangingParams) { 3321 // When the UWBS supports Fira 2.0+, the application has configured a relative UWB 3322 // initation time, but not configured an absolute UWB initiation time, we must fetch 3323 // the UWBS timestamp (to compute the absolute UWB initiation time). 3324 if (getUwbsFiraProtocolVersion(mChipId).getMajor() >= 2) { 3325 if (mParams instanceof FiraOpenSessionParams) { 3326 FiraOpenSessionParams firaOpenSessionParams = (FiraOpenSessionParams) mParams; 3327 if (firaOpenSessionParams.getInitiationTime() != 0 3328 && firaOpenSessionParams.getAbsoluteInitiationTime() == 0) { 3329 this.mNeedsQueryUwbsTimestamp = true; 3330 } 3331 } else if (mParams instanceof CccOpenRangingParams 3332 && mUwbInjector.getDeviceConfigFacade() 3333 .isCccAbsoluteUwbInitiationTimeEnabled()) { 3334 // When CccStartRangingParams is present; we check only for it's fields, 3335 // since its values overrides the earlier CccOpenRangingParams. 3336 if (startRangingParams != null 3337 && startRangingParams instanceof CccStartRangingParams) { 3338 CccStartRangingParams cccStartRangingParams = 3339 (CccStartRangingParams) startRangingParams; 3340 if (cccStartRangingParams.getInitiationTimeMs() != 0 3341 && cccStartRangingParams.getAbsoluteInitiationTimeUs() == 0) { 3342 this.mNeedsQueryUwbsTimestamp = true; 3343 } 3344 } else { 3345 CccOpenRangingParams cccOpenRangingParams = (CccOpenRangingParams) mParams; 3346 if (cccOpenRangingParams.getInitiationTimeMs() != 0 3347 && cccOpenRangingParams.getAbsoluteInitiationTimeUs() == 0) { 3348 this.mNeedsQueryUwbsTimestamp = true; 3349 } 3350 } 3351 } else if (mParams instanceof AliroOpenRangingParams 3352 && mUwbInjector.getDeviceConfigFacade() 3353 .isCccAbsoluteUwbInitiationTimeEnabled()) { // Re-use CCC flag for ALIRO 3354 // When AliroStartRangingParams is present; we check only for it's fields, 3355 // since its values overrides the earlier AliroOpenRangingParams. 3356 if (startRangingParams != null 3357 && startRangingParams instanceof AliroStartRangingParams) { 3358 AliroStartRangingParams aliroStartRangingParams = 3359 (AliroStartRangingParams) startRangingParams; 3360 if (aliroStartRangingParams.getInitiationTimeMs() != 0 3361 && aliroStartRangingParams.getAbsoluteInitiationTimeUs() == 0) { 3362 this.mNeedsQueryUwbsTimestamp = true; 3363 } 3364 } else { 3365 AliroOpenRangingParams aliroOpenRangingParams = 3366 (AliroOpenRangingParams) mParams; 3367 if (aliroOpenRangingParams.getInitiationTimeMs() != 0 3368 && aliroOpenRangingParams.getAbsoluteInitiationTimeUs() == 0) { 3369 this.mNeedsQueryUwbsTimestamp = true; 3370 } 3371 } 3372 } 3373 } 3374 } 3375 3376 /** 3377 * Computes an absolute UWB initiation time, if it's needed. 3378 */ setAbsoluteInitiationTimeIfNeeded()3379 public void setAbsoluteInitiationTimeIfNeeded() { 3380 if (this.mNeedsQueryUwbsTimestamp) { 3381 // Query the UWBS timestamp and add the relative initiation time 3382 // stored in the FiraOpenSessionParams, to get the absolute 3383 // initiation time to be configured. 3384 long uwbsTimestamp = 3385 mUwbInjector.getUwbServiceCore().queryUwbsTimestampMicros(); 3386 computeAbsoluteInitiationTime(uwbsTimestamp); 3387 } 3388 } 3389 3390 /** 3391 * For Fira 2.0+ controller devices, replace the reference Session's SessionID with 3392 * its SessionToken, in the SessionTimeBase AppConfig parameter. 3393 */ updateFiraParamsForSessionTimeBase(int sessionToken)3394 public void updateFiraParamsForSessionTimeBase(int sessionToken) { 3395 if (mParams instanceof FiraOpenSessionParams) { 3396 FiraOpenSessionParams firaOpenSessionParams = (FiraOpenSessionParams) mParams; 3397 int deviceRole = firaOpenSessionParams.getDeviceRole(); 3398 if (deviceRole == FiraParams.RANGING_DEVICE_TYPE_CONTROLLER 3399 && UwbUtil.isBitSet(firaOpenSessionParams.getReferenceTimeBase(), 3400 FiraParams.SESSION_TIME_BASE_REFERENCE_FEATURE_ENABLED)) { 3401 this.mParams = ((FiraOpenSessionParams) mParams).toBuilder().setSessionTimeBase( 3402 firaOpenSessionParams.getReferenceTimeBase(), sessionToken, 3403 firaOpenSessionParams.getSessionOffsetInMicroSeconds()) 3404 .build(); 3405 } 3406 } 3407 } 3408 3409 /** 3410 * Compute absolute initiation time, by doing a sum of the UWBS Timestamp (in micro-seconds) 3411 * and the relative initiation time (in milli-seconds). This method should be 3412 * called only for FiRa UCI ProtocolVersion >= 2.0 devices. 3413 */ computeAbsoluteInitiationTime(long uwbsTimestamp)3414 public void computeAbsoluteInitiationTime(long uwbsTimestamp) { 3415 if (this.mNeedsQueryUwbsTimestamp) { 3416 if (mParams instanceof FiraOpenSessionParams) { 3417 FiraOpenSessionParams firaOpenSessionParams = (FiraOpenSessionParams) mParams; 3418 this.mParams = ((FiraOpenSessionParams) mParams).toBuilder() 3419 .setAbsoluteInitiationTime(uwbsTimestamp 3420 + (firaOpenSessionParams.getInitiationTime() * 1000)) 3421 .build(); 3422 } else if (mParams instanceof CccOpenRangingParams) { 3423 CccOpenRangingParams cccOpenRangingParams = (CccOpenRangingParams) mParams; 3424 this.mParams = ((CccOpenRangingParams) mParams).toBuilder() 3425 .setAbsoluteInitiationTimeUs(uwbsTimestamp 3426 + (cccOpenRangingParams.getInitiationTimeMs() * 1000)) 3427 .build(); 3428 } else if (mParams instanceof AliroOpenRangingParams) { 3429 AliroOpenRangingParams aliroOpenRangingParams = 3430 (AliroOpenRangingParams) mParams; 3431 this.mParams = ((AliroOpenRangingParams) mParams).toBuilder() 3432 .setAbsoluteInitiationTimeUs(uwbsTimestamp 3433 + (aliroOpenRangingParams.getInitiationTimeMs() * 1000)) 3434 .build(); 3435 } 3436 this.mNeedsAppConfigUpdate = true; 3437 } 3438 } 3439 3440 /** 3441 * Reset the computed absolute initiation time, only when it was computed and set by this 3442 * class (it should not be reset when it was provided by the application). 3443 */ resetAbsoluteInitiationTime()3444 public void resetAbsoluteInitiationTime() { 3445 if (this.mNeedsQueryUwbsTimestamp) { 3446 if (mParams instanceof FiraOpenSessionParams) { 3447 // Reset the absolute Initiation time, so that it's re-computed if start 3448 // ranging is called in the future for this UWB session. 3449 this.mParams = ((FiraOpenSessionParams) mParams).toBuilder() 3450 .setAbsoluteInitiationTime(0) 3451 .build(); 3452 } else if (mParams instanceof CccOpenRangingParams) { 3453 this.mParams = ((CccOpenRangingParams) mParams).toBuilder() 3454 .setAbsoluteInitiationTimeUs(0) 3455 .build(); 3456 } else if (mParams instanceof AliroOpenRangingParams) { 3457 this.mParams = ((AliroOpenRangingParams) mParams).toBuilder() 3458 .setAbsoluteInitiationTimeUs(0) 3459 .build(); 3460 } 3461 this.mNeedsQueryUwbsTimestamp = false; 3462 } 3463 } 3464 updateFiraParamsOnReconfigure(FiraRangingReconfigureParams reconfigureParams)3465 public void updateFiraParamsOnReconfigure(FiraRangingReconfigureParams reconfigureParams) { 3466 // Need to update the reconfigure params from the FiraRangingReconfigureParams for 3467 // FiRa session. 3468 FiraOpenSessionParams.Builder newParamsBuilder = 3469 new FiraOpenSessionParams.Builder((FiraOpenSessionParams) mParams); 3470 if (reconfigureParams.getBlockStrideLength() != null) { 3471 newParamsBuilder.setBlockStrideLength(reconfigureParams.getBlockStrideLength()); 3472 } 3473 if (reconfigureParams.getRangeDataNtfConfig() != null) { 3474 newParamsBuilder.setRangeDataNtfConfig(reconfigureParams.getRangeDataNtfConfig()); 3475 } 3476 if (reconfigureParams.getRangeDataProximityNear() != null) { 3477 newParamsBuilder.setRangeDataNtfProximityNear( 3478 reconfigureParams.getRangeDataProximityNear()); 3479 } 3480 if (reconfigureParams.getRangeDataProximityFar() != null) { 3481 newParamsBuilder.setRangeDataNtfProximityFar( 3482 reconfigureParams.getRangeDataProximityFar()); 3483 } 3484 if (reconfigureParams.getRangeDataAoaAzimuthLower() != null) { 3485 newParamsBuilder.setRangeDataNtfAoaAzimuthLower( 3486 reconfigureParams.getRangeDataAoaAzimuthLower()); 3487 } 3488 if (reconfigureParams.getRangeDataAoaAzimuthUpper() != null) { 3489 newParamsBuilder.setRangeDataNtfAoaAzimuthUpper( 3490 reconfigureParams.getRangeDataAoaAzimuthUpper()); 3491 } 3492 if (reconfigureParams.getRangeDataAoaElevationLower() != null) { 3493 newParamsBuilder.setRangeDataNtfAoaElevationLower( 3494 reconfigureParams.getRangeDataAoaElevationLower()); 3495 } 3496 if (reconfigureParams.getRangeDataAoaElevationUpper() != null) { 3497 newParamsBuilder.setRangeDataNtfAoaElevationUpper( 3498 reconfigureParams.getRangeDataAoaElevationUpper()); 3499 } 3500 this.mParams = newParamsBuilder.build(); 3501 } 3502 3503 // Return the Ranging Interval (Fira 2.0: Ranging Duration) in milliseconds. updateCccParamsOnReconfigure(CccRangingReconfiguredParams reconfigureParams)3504 public void updateCccParamsOnReconfigure(CccRangingReconfiguredParams reconfigureParams) { 3505 // Need to update the reconfigure params from the CccRangingReconfiguredParams for 3506 // Ccc session. 3507 CccOpenRangingParams.Builder newParamsBuilder = 3508 new CccOpenRangingParams.Builder((CccOpenRangingParams) mParams); 3509 if (reconfigureParams.getRangeDataNtfConfig() != null) { 3510 newParamsBuilder.setRangeDataNtfConfig(reconfigureParams.getRangeDataNtfConfig()); 3511 } 3512 if (reconfigureParams.getRangeDataProximityNear() != null) { 3513 newParamsBuilder.setRangeDataNtfProximityNear( 3514 reconfigureParams.getRangeDataProximityNear()); 3515 } 3516 if (reconfigureParams.getRangeDataProximityFar() != null) { 3517 newParamsBuilder.setRangeDataNtfProximityFar( 3518 reconfigureParams.getRangeDataProximityFar()); 3519 } 3520 if (reconfigureParams.getRangeDataAoaAzimuthLower() != null) { 3521 newParamsBuilder.setRangeDataNtfAoaAzimuthLower( 3522 reconfigureParams.getRangeDataAoaAzimuthLower()); 3523 } 3524 if (reconfigureParams.getRangeDataAoaAzimuthUpper() != null) { 3525 newParamsBuilder.setRangeDataNtfAoaAzimuthUpper( 3526 reconfigureParams.getRangeDataAoaAzimuthUpper()); 3527 } 3528 if (reconfigureParams.getRangeDataAoaElevationLower() != null) { 3529 newParamsBuilder.setRangeDataNtfAoaElevationLower( 3530 reconfigureParams.getRangeDataAoaElevationLower()); 3531 } 3532 if (reconfigureParams.getRangeDataAoaElevationUpper() != null) { 3533 newParamsBuilder.setRangeDataNtfAoaElevationUpper( 3534 reconfigureParams.getRangeDataAoaElevationUpper()); 3535 } 3536 this.mParams = newParamsBuilder.build(); 3537 } 3538 getCurrentFiraRangingIntervalMs()3539 public int getCurrentFiraRangingIntervalMs() { 3540 FiraOpenSessionParams firaOpenSessionParams = (FiraOpenSessionParams) mParams; 3541 return firaOpenSessionParams.getRangingIntervalMs() 3542 * (firaOpenSessionParams.getBlockStrideLength() + 1); 3543 } 3544 getProtocolName()3545 public String getProtocolName() { 3546 return this.mProtocolName; 3547 } 3548 getIUwbRangingCallbacks()3549 public IUwbRangingCallbacks getIUwbRangingCallbacks() { 3550 return this.mIUwbRangingCallbacks; 3551 } 3552 getSessionState()3553 public int getSessionState() { 3554 return this.mSessionState; 3555 } 3556 setSessionState(int state)3557 public void setSessionState(int state) { 3558 this.mSessionState = state; 3559 } 3560 getRfTestStartSessionParams()3561 public RfTestStartSessionParams getRfTestStartSessionParams() { 3562 return this.mRfTestStartSessionParams; 3563 } 3564 setRfTestStartSessionParams(RfTestStartSessionParams params)3565 public void setRfTestStartSessionParams(RfTestStartSessionParams params) { 3566 this.mRfTestStartSessionParams = params; 3567 } 3568 getStackSessionPriority()3569 public int getStackSessionPriority() { 3570 return this.mStackSessionPriority; 3571 } 3572 setStackSessionPriority(int priority)3573 public void setStackSessionPriority(int priority) { 3574 this.mStackSessionPriority = priority; 3575 } 3576 getNeedsAppConfigUpdate()3577 public boolean getNeedsAppConfigUpdate() { 3578 return this.mNeedsAppConfigUpdate; 3579 } 3580 3581 /** Reset the needsAppConfigUpdate flag to false. */ resetNeedsAppConfigUpdate()3582 public void resetNeedsAppConfigUpdate() { 3583 this.mNeedsAppConfigUpdate = false; 3584 } 3585 getNeedsQueryUwbsTimestamp()3586 public boolean getNeedsQueryUwbsTimestamp() { 3587 return this.mNeedsQueryUwbsTimestamp; 3588 } 3589 getRemoteMacAddressList()3590 public Set<Long> getRemoteMacAddressList() { 3591 return mReceivedDataInfoMap.keySet(); 3592 } 3593 isDataDeliveryPermissionCheckNeeded()3594 public boolean isDataDeliveryPermissionCheckNeeded() { 3595 return mDataDeliveryPermissionCheckNeeded; 3596 } 3597 setDataDeliveryPermissionCheckNeeded(boolean permissionCheckNeeded)3598 public void setDataDeliveryPermissionCheckNeeded(boolean permissionCheckNeeded) { 3599 mDataDeliveryPermissionCheckNeeded = permissionCheckNeeded; 3600 } setMulticastListUpdateStatus( UwbMulticastListUpdateStatus multicastListUpdateStatus)3601 public void setMulticastListUpdateStatus( 3602 UwbMulticastListUpdateStatus multicastListUpdateStatus) { 3603 mMulticastListUpdateStatus = multicastListUpdateStatus; 3604 } 3605 getMulticastListUpdateStatus()3606 public UwbMulticastListUpdateStatus getMulticastListUpdateStatus() { 3607 return mMulticastListUpdateStatus; 3608 } 3609 convertProtolNameToProfileType(String protocolName)3610 private int convertProtolNameToProfileType(String protocolName) { 3611 if (protocolName.equals(FiraParams.PROTOCOL_NAME)) { 3612 return UwbStatsLog.UWB_SESSION_INITIATED__PROFILE__FIRA; 3613 } else if (protocolName.equals(CccParams.PROTOCOL_NAME)) { 3614 return UwbStatsLog.UWB_SESSION_INITIATED__PROFILE__CCC; 3615 } else if (protocolName.equals(AliroParams.PROTOCOL_NAME)) { 3616 return UwbStatsLog.UWB_SESSION_INITIATED__PROFILE__ALIRO; 3617 } else { 3618 return UwbStatsLog.UWB_SESSION_INITIATED__PROFILE__CUSTOMIZED; 3619 } 3620 } 3621 getProfileType()3622 public int getProfileType() { 3623 return mProfileType; 3624 } 3625 getParallelSessionCount()3626 public int getParallelSessionCount() { 3627 if (mSessionTable.containsKey(mSessionHandle)) { 3628 return getSessionCount() - 1; 3629 } 3630 return getSessionCount(); 3631 } 3632 getBinder()3633 public IBinder getBinder() { 3634 return mIBinder; 3635 } 3636 getWaitObj()3637 public WaitObj getWaitObj() { 3638 return mWaitObj; 3639 } 3640 hasNonPrivilegedFgAppOrService()3641 public boolean hasNonPrivilegedFgAppOrService() { 3642 return mHasNonPrivilegedFgAppOrService; 3643 } 3644 setHasNonPrivilegedFgAppOrService(boolean hasNonPrivilegedFgAppOrService)3645 public void setHasNonPrivilegedFgAppOrService(boolean hasNonPrivilegedFgAppOrService) { 3646 mHasNonPrivilegedFgAppOrService = hasNonPrivilegedFgAppOrService; 3647 } 3648 3649 /** 3650 * Starts a timer to detect if the error streak is longer than 3651 * {@link UwbSession#mRangingErrorStreakTimeoutMs }. The session is ended when the alarm 3652 * triggers. 3653 */ startRangingResultErrorStreakTimerIfNotSet()3654 public void startRangingResultErrorStreakTimerIfNotSet() { 3655 // Start a timer on first failure to detect continuous failures. 3656 if (mRangingResultErrorStreakTimerListener == null) { 3657 mRangingResultErrorStreakTimerListener = () -> { 3658 Log.w(TAG, "Continuous errors or no ranging results detected for " 3659 + mRangingErrorStreakTimeoutMs + " ms." 3660 + " Stopping session"); 3661 if (getSessionState() == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 3662 stopRangingInternal(mSessionHandle, true /* triggeredBySystemPolicy */); 3663 } else { 3664 Log.i(TAG, "Session is not in an active state"); 3665 } 3666 }; 3667 Log.v(TAG, "Starting error timer for " 3668 + mRangingErrorStreakTimeoutMs + " ms."); 3669 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 3670 mUwbInjector.getElapsedSinceBootMillis() 3671 + mRangingErrorStreakTimeoutMs, 3672 RANGING_RESULT_ERROR_STREAK_TIMER_TAG, 3673 mRangingResultErrorStreakTimerListener, mEventTask); 3674 } 3675 } 3676 stopRangingResultErrorStreakTimerIfSet()3677 public void stopRangingResultErrorStreakTimerIfSet() { 3678 // Cancel error streak timer on any success. 3679 if (mRangingResultErrorStreakTimerListener != null) { 3680 mAlarmManager.cancel(mRangingResultErrorStreakTimerListener); 3681 mRangingResultErrorStreakTimerListener = null; 3682 } 3683 } 3684 removeControleeDueToErrorStreakTimeout(UwbAddress address)3685 private void removeControleeDueToErrorStreakTimeout(UwbAddress address) { 3686 reconfigureInternal(mSessionHandle, 3687 new FiraRangingReconfigureParams.Builder() 3688 .setAction(MULTICAST_LIST_UPDATE_ACTION_DELETE) 3689 .setAddressList(new UwbAddress[] { address }) 3690 .setSubSessionIdList(new int[] { 0 }) 3691 .build(), 3692 Reconfiguration.Reason.LOST_CONNECTION); 3693 } 3694 3695 /** 3696 * Same as {@link UwbSession#startRangingResultErrorStreakTimerIfNotSet()}, except 3697 * starts multiple timers on a per-controlee basis for two-way ranging sessions. The 3698 * controlee will be removed from the session when the alarm triggers. The session is ended 3699 * only when the last controlee is removed. 3700 * 3701 * @param address : Address of the controlee to associate the timer with. 3702 */ startRangingResultErrorStreakTimerIfNotSet(UwbAddress address)3703 public void startRangingResultErrorStreakTimerIfNotSet(UwbAddress address) { 3704 if (!mControlees.containsKey(address)) { 3705 Log.w(TAG, "Attempted to start error timer for controlee " + address 3706 + " that is not in the session."); 3707 return; 3708 } 3709 if (mMulticastRangingErrorStreakTimerListeners.containsKey(address)) { 3710 return; 3711 } 3712 Log.v(TAG, "Starting error timer for controlee " + address + " for " 3713 + mRangingErrorStreakTimeoutMs + " ms."); 3714 3715 AlarmManager.OnAlarmListener onAlarm = () -> { 3716 Log.w(TAG, "Continuous errors or no ranging results detected from controlee " 3717 + address + " for " + mRangingErrorStreakTimeoutMs + " ms."); 3718 3719 synchronized (mControleeCountLock) { 3720 if (mControlees.size() - mControleesPendingDisconnection.size() == 1) { 3721 Log.w(TAG, "Last controlee in session has disconnected, stopping session"); 3722 if (getSessionState() == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 3723 stopRangingInternal(mSessionHandle, true /* triggeredBySystemPolicy */); 3724 } else { 3725 Log.i(TAG, "Session is not in an active state"); 3726 } 3727 } else { 3728 mControleesPendingDisconnection.add(address); 3729 removeControleeDueToErrorStreakTimeout(address); 3730 } 3731 } 3732 }; 3733 3734 mMulticastRangingErrorStreakTimerListeners.put(address, onAlarm); 3735 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 3736 mUwbInjector.getElapsedSinceBootMillis() + mRangingErrorStreakTimeoutMs, 3737 RANGING_RESULT_ERROR_STREAK_TIMER_TAG, 3738 onAlarm, 3739 mEventTask); 3740 } 3741 3742 /** 3743 * Stops the timer associated with a controlee, if set. 3744 * This function will never stop the session. 3745 * 3746 * @param address : Address of the controlee whose timer to stop. 3747 */ stopRangingResultErrorStreakTimerIfSet(UwbAddress address)3748 public void stopRangingResultErrorStreakTimerIfSet(UwbAddress address) { 3749 if (!mControlees.containsKey(address)) { 3750 Log.w(TAG, "Attempted to stop error timer for controlee " + address 3751 + "that is not in the session"); 3752 return; 3753 } 3754 if (!mMulticastRangingErrorStreakTimerListeners.containsKey(address)) { 3755 return; 3756 } 3757 mAlarmManager.cancel(mMulticastRangingErrorStreakTimerListeners.get(address)); 3758 mMulticastRangingErrorStreakTimerListeners.remove(address); 3759 } 3760 3761 /** 3762 * Starts a timer to detect if the app that started the UWB session is in the background 3763 * for longer than {@link UwbSession#NON_PRIVILEGED_BG_APP_TIMEOUT_MS}. 3764 */ startNonPrivilegedBgAppTimerIfNotSet()3765 private void startNonPrivilegedBgAppTimerIfNotSet() { 3766 // Start a timer when the non-privileged app goes into the background. 3767 if (mNonPrivilegedBgAppTimerListener == null) { 3768 mNonPrivilegedBgAppTimerListener = () -> { 3769 Log.w(TAG, "Non-privileged app in background for longer than timeout - " 3770 + " Stopping session"); 3771 if (getSessionState() == UwbUciConstants.UWB_SESSION_STATE_ACTIVE) { 3772 stopRangingInternal(mSessionHandle, true /* triggeredBySystemPolicy */); 3773 } else { 3774 Log.i(TAG, "Session is not in an active state"); 3775 } 3776 }; 3777 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 3778 mUwbInjector.getElapsedSinceBootMillis() 3779 + NON_PRIVILEGED_BG_APP_TIMEOUT_MS, 3780 NON_PRIVILEGED_BG_APP_TIMER_TAG, 3781 mNonPrivilegedBgAppTimerListener, mEventTask); 3782 } 3783 } 3784 stopNonPrivilegedBgAppTimerIfSet()3785 private void stopNonPrivilegedBgAppTimerIfSet() { 3786 // Stop the timer when the non-privileged app goes into the foreground. 3787 if (mNonPrivilegedBgAppTimerListener != null) { 3788 mAlarmManager.cancel(mNonPrivilegedBgAppTimerListener); 3789 mNonPrivilegedBgAppTimerListener = null; 3790 } 3791 } 3792 stopTimers()3793 private void stopTimers() { 3794 // Reset any stored error streak or non-privileged background app timestamps. 3795 stopRangingResultErrorStreakTimerIfSet(); 3796 for (UwbAddress address : getControleesWithOngoingRangingErrorStreak()) { 3797 stopRangingResultErrorStreakTimerIfSet(address); 3798 } 3799 stopNonPrivilegedBgAppTimerIfSet(); 3800 } 3801 reconfigureFiraSessionOnFgStateChange()3802 public void reconfigureFiraSessionOnFgStateChange() { 3803 // Reconfigure the session to change notification control when the app transitions 3804 // from fg to bg and vice versa. 3805 FiraRangingReconfigureParams.Builder builder = 3806 new FiraRangingReconfigureParams.Builder(); 3807 // If app is in fg, use the configured ntf control, else disable. 3808 if (mHasNonPrivilegedFgAppOrService) { 3809 FiraOpenSessionParams params = (FiraOpenSessionParams) mParams; 3810 int rangeDataNtfConfig = params.getRangeDataNtfConfig(); 3811 builder.setRangeDataNtfConfig(rangeDataNtfConfig); 3812 if (rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG 3813 || rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG) { 3814 builder 3815 .setRangeDataProximityNear(params.getRangeDataNtfProximityNear()) 3816 .setRangeDataProximityFar(params.getRangeDataNtfProximityFar()); 3817 } 3818 } else { 3819 builder.setRangeDataNtfConfig(FiraParams.RANGE_DATA_NTF_CONFIG_DISABLE); 3820 } 3821 FiraRangingReconfigureParams reconfigureParams = builder.build(); 3822 reconfigureInternal(mSessionHandle, reconfigureParams, 3823 Reconfiguration.Reason.FG_STATE_CHANGE); 3824 3825 if (!mUwbInjector.getDeviceConfigFacade().isBackgroundRangingEnabled()) { 3826 Log.d(TAG, "reconfigureFiraSessionOnFgStateChange - System policy disallows for " 3827 + "non fg 3p apps"); 3828 // When a non-privileged app goes into the background, start a timer (that will stop 3829 // the ranging session). If the app goes back into the foreground, the timer will 3830 // get reset (but any stopped UWB session will not be auto-resumed). 3831 if (!mHasNonPrivilegedFgAppOrService) { 3832 startNonPrivilegedBgAppTimerIfNotSet(); 3833 } else { 3834 stopNonPrivilegedBgAppTimerIfSet(); 3835 } 3836 } else { 3837 Log.d(TAG, "reconfigureFiraSessionOnFgStateChange - System policy allows for " 3838 + "non fg 3p apps"); 3839 } 3840 } 3841 getOperationType()3842 public int getOperationType() { 3843 return mOperationType; 3844 } 3845 setOperationType(int type)3846 public void setOperationType(int type) { 3847 mOperationType = type; 3848 } 3849 getLastSessionStatusNtfReasonCode()3850 public int getLastSessionStatusNtfReasonCode() { 3851 return mLastSessionStatusNtfReasonCode; 3852 } 3853 setLastSessionStatusNtfReasonCode(int lastSessionStatusNtfReasonCode)3854 public void setLastSessionStatusNtfReasonCode(int lastSessionStatusNtfReasonCode) { 3855 mLastSessionStatusNtfReasonCode = lastSessionStatusNtfReasonCode; 3856 } 3857 3858 /** Creates a filter engine based on the device configuration. */ createFilterEngine()3859 public UwbFilterEngine createFilterEngine() { 3860 if (mParams instanceof FiraOpenSessionParams) { 3861 FiraOpenSessionParams firaParams = (FiraOpenSessionParams) mParams; 3862 if (firaParams.getFilterType() == FILTER_TYPE_NONE) { 3863 return null; /* Bail early. App requested no engine. */ 3864 } 3865 } 3866 3867 return mUwbInjector.createFilterEngine(mPoseSource); 3868 } 3869 3870 /** Updates the pose information if an ApplicationPoseSource is being used. */ updatePose(FiraPoseUpdateParams updateParams)3871 public void updatePose(FiraPoseUpdateParams updateParams) { 3872 if (mPoseSource instanceof ApplicationPoseSource) { 3873 ApplicationPoseSource aps = (ApplicationPoseSource) mPoseSource; 3874 aps.applyPose(updateParams.getPoseInfo()); 3875 } else { 3876 throw new IllegalStateException("Session not configured for application poses."); 3877 } 3878 } 3879 3880 @Override binderDied()3881 public void binderDied() { 3882 Log.i(TAG, "binderDied : getSessionId is getSessionId() " + getSessionId()); 3883 3884 synchronized (UwbSessionManager.this) { 3885 int status = mNativeUwbManager.deInitSession(getSessionId(), getChipId()); 3886 mUwbMetrics.logRangingCloseEvent(this, status); 3887 if (status == UwbUciConstants.STATUS_CODE_OK) { 3888 removeSession(this); 3889 Log.i(TAG, 3890 "binderDied : Fira/CCC/ALIRO Session counts currently are " 3891 + getFiraSessionCount() 3892 + "/" + getCccSessionCount() 3893 + "/" + getAliroSessionCount()); 3894 } else { 3895 Log.e(TAG, 3896 "binderDied : sessionDeinit Failure because of NativeSessionDeinit " 3897 + "Error"); 3898 } 3899 } 3900 } 3901 3902 /** 3903 * Cleans up resources held by this object. 3904 */ close()3905 public void close() { 3906 if (this.mAcquiredDefaultPose) { 3907 for (UwbControlee controlee : mControlees.values()) { 3908 controlee.close(); 3909 } 3910 synchronized (mControleeCountLock) { 3911 mControlees.clear(); 3912 mControleesPendingDisconnection.clear(); 3913 } 3914 3915 this.mAcquiredDefaultPose = false; 3916 mUwbInjector.releasePoseSource(); 3917 } 3918 3919 mSendDataInfoMap.clear(); 3920 clearReceivedDataInfo(); 3921 } 3922 3923 /** 3924 * Gets the pose source for this session. This may be the default pose source provided 3925 * by UwbInjector.java when the session was created, or a specialized pose source later 3926 * requested by the application. 3927 */ getPoseSource()3928 public IPoseSource getPoseSource() { 3929 return mPoseSource; 3930 } 3931 3932 @Override toString()3933 public String toString() { 3934 return "UwbSession: { Session Id: " + getSessionId() 3935 + ", Handle: " + getSessionHandle() 3936 + ", Protocol: " + getProtocolName() 3937 + ", State: " + getSessionState() 3938 + ", Data Send Sequence Number: " + mDataSndSequenceNumber 3939 + ", Params: " + getParams() 3940 + ", AttributionSource: " + getAttributionSource() 3941 + " }"; 3942 } 3943 } 3944 3945 // TODO: refactor the async operation flow. 3946 // Wrapper for unit test. 3947 @VisibleForTesting 3948 static class WaitObj { WaitObj()3949 WaitObj() { 3950 } 3951 blockingWait()3952 void blockingWait() throws InterruptedException { 3953 wait(); 3954 } 3955 blockingNotify()3956 void blockingNotify() { 3957 notify(); 3958 } 3959 } 3960 3961 /** 3962 * Dump the UWB session manager debug info 3963 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)3964 public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3965 pw.println("---- Dump of UwbSessionManager ----"); 3966 pw.println("Active sessions: "); 3967 for (UwbSession uwbSession : mSessionTable.values()) { 3968 pw.println(uwbSession); 3969 } 3970 pw.println("Recently closed sessions: "); 3971 for (UwbSession uwbSession: mDbgRecentlyClosedSessions.getEntries()) { 3972 pw.println(uwbSession); 3973 } 3974 List<Integer> nonPrivilegedSessionIds = 3975 mNonPrivilegedUidToFiraSessionsTable.entrySet() 3976 .stream() 3977 .map(e -> e.getValue() 3978 .stream() 3979 .map(UwbSession::getSessionId) 3980 .collect(Collectors.toList())) 3981 .flatMap(Collection::stream) 3982 .collect(Collectors.toList()); 3983 pw.println("Non Privileged Fira Session Ids: " + nonPrivilegedSessionIds); 3984 pw.println("---- Dump of UwbSessionManager ----"); 3985 } 3986 getComputedMacAddress(UwbAddress address)3987 private static byte[] getComputedMacAddress(UwbAddress address) { 3988 if (!SdkLevel.isAtLeastU()) { 3989 return TlvUtil.getReverseBytes(address.toBytes()); 3990 } 3991 return address.toBytes(); 3992 } 3993 } 3994