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