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 android.content.AttributionSource; 19 import android.util.SparseArray; 20 import android.uwb.RangingMeasurement; 21 22 import com.android.server.uwb.UwbSessionManager.UwbSession; 23 import com.android.server.uwb.data.UwbDlTDoAMeasurement; 24 import com.android.server.uwb.data.UwbOwrAoaMeasurement; 25 import com.android.server.uwb.data.UwbRangingData; 26 import com.android.server.uwb.data.UwbTwoWayMeasurement; 27 import com.android.server.uwb.data.UwbUciConstants; 28 import com.android.server.uwb.proto.UwbStatsLog; 29 30 import com.google.common.collect.ImmutableSet; 31 import com.google.uwb.support.base.Params; 32 import com.google.uwb.support.ccc.CccOpenRangingParams; 33 import com.google.uwb.support.fira.FiraOpenSessionParams; 34 import com.google.uwb.support.fira.FiraParams; 35 36 import java.io.FileDescriptor; 37 import java.io.PrintWriter; 38 import java.util.ArrayDeque; 39 import java.util.Calendar; 40 import java.util.Deque; 41 42 /** 43 * A class to collect and report UWB metrics. 44 */ 45 public class UwbMetrics { 46 private static final String TAG = "UwbMetrics"; 47 48 private static final int MAX_RANGING_SESSIONS = 128; 49 private static final int MAX_RANGING_REPORTS = 1024; 50 public static final int INVALID_DISTANCE = 0xFFFF; 51 private static final int ONE_SECOND_IN_MS = 1000; 52 private static final int TEN_SECOND_IN_MS = 10 * 1000; 53 private static final int ONE_MIN_IN_MS = 60 * 1000; 54 private static final int TEN_MIN_IN_MS = 600 * 1000; 55 private static final int ONE_HOUR_IN_MS = 3600 * 1000; 56 private static final ImmutableSet<Integer> SUPPORTED_RANGING_MEASUREMENT_TYPES = ImmutableSet 57 .of((int) UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY, 58 (int) UwbUciConstants.RANGING_MEASUREMENT_TYPE_DL_TDOA, 59 (int) UwbUciConstants.RANGING_MEASUREMENT_TYPE_OWR_AOA); 60 private final UwbInjector mUwbInjector; 61 private final Deque<RangingSessionStats> mRangingSessionList = new ArrayDeque<>(); 62 private final SparseArray<RangingSessionStats> mOpenedSessionMap = new SparseArray<>(); 63 private final Deque<RangingReportEvent> mRangingReportList = new ArrayDeque<>(); 64 private int mNumApps = 0; 65 private long mLastRangingDataLogTimeMs; 66 private final Object mLock = new Object(); 67 68 /** 69 * The class storing the stats of a ranging session. 70 */ 71 public class RangingSessionStats { 72 private int mSessionId; 73 private int mChannel = 9; 74 private long mInitTimeWallClockMs; 75 private long mStartTimeSinceBootMs; 76 private int mInitLatencyMs; 77 private int mInitStatus; 78 private int mRangingStatus; 79 private int mActiveDuration; 80 private int mRangingCount; 81 private int mValidRangingCount; 82 private boolean mHasValidRangingSinceStart; 83 private int mStartCount; 84 private int mStartFailureCount; 85 private int mStartNoValidReportCount; 86 private int mStsType = UwbStatsLog.UWB_SESSION_INITIATED__STS__UNKNOWN_STS; 87 private boolean mIsInitiator; 88 private boolean mIsController; 89 private boolean mIsDiscoveredByFramework = false; 90 private boolean mIsOutOfBand = true; 91 private int mRangingIntervalMs; 92 private int mParallelSessionCount; 93 private int mRxPacketCount; 94 private int mTxPacketCount; 95 private int mRxErrorCount; 96 private int mTxErrorCount; 97 private int mRxToUpperLayerCount; 98 private int mRangingType = UwbStatsLog 99 .UWB_RANGING_MEASUREMENT_RECEIVED__RANGING_TYPE__TYPE_UNKNOWN; 100 private int mFilterConfigValue = composeFilterConfigValue(); 101 private AttributionSource mAttributionSource; 102 RangingSessionStats(int sessionId, AttributionSource attributionSource, int parallelSessionCount)103 RangingSessionStats(int sessionId, AttributionSource attributionSource, 104 int parallelSessionCount) { 105 mSessionId = sessionId; 106 mInitTimeWallClockMs = mUwbInjector.getWallClockMillis(); 107 mAttributionSource = attributionSource; 108 mParallelSessionCount = parallelSessionCount; 109 } 110 composeFilterConfigValue()111 private int composeFilterConfigValue() { 112 DeviceConfigFacade cfg = mUwbInjector.getDeviceConfigFacade(); 113 int filter_enabled = cfg.isEnableFilters() ? 1 : 0; 114 int enable_azimuth_mirroring = (cfg.isEnableBackAzimuth() ? 1 : 0) << 1; 115 int enable_primer_aoa = (cfg.isEnablePrimerAoA() ? 1 : 0) << 2; 116 int enable_primer_est_elevation = (cfg.isEnablePrimerEstElevation() ? 1 : 0) << 3; 117 int enable_primer_fov = (cfg.isEnablePrimerFov() ? 1 : 0) << 4; 118 int predict_rear_azimuths = (cfg.isEnableBackAzimuthMasking() ? 1 : 0) << 5; 119 return filter_enabled + enable_azimuth_mirroring + enable_primer_aoa 120 + enable_primer_est_elevation + enable_primer_fov + predict_rear_azimuths; 121 } 122 123 /** 124 * Parse UWB profile parameters 125 */ parseParams(Params params)126 public void parseParams(Params params) { 127 if (params instanceof FiraOpenSessionParams) { 128 parseFiraParams((FiraOpenSessionParams) params); 129 } else if (params instanceof CccOpenRangingParams) { 130 parseCccParams((CccOpenRangingParams) params); 131 } 132 } 133 parseFiraParams(FiraOpenSessionParams params)134 private void parseFiraParams(FiraOpenSessionParams params) { 135 if (params.getStsConfig() == FiraParams.STS_CONFIG_STATIC) { 136 mStsType = UwbStatsLog.UWB_SESSION_INITIATED__STS__STATIC; 137 } else if (params.getStsConfig() == FiraParams.STS_CONFIG_DYNAMIC) { 138 mStsType = UwbStatsLog.UWB_SESSION_INITIATED__STS__DYNAMIC; 139 } else { 140 mStsType = UwbStatsLog.UWB_SESSION_INITIATED__STS__PROVISIONED; 141 } 142 143 mIsInitiator = params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_INITIATOR; 144 mIsController = params.getDeviceType() == FiraParams.RANGING_DEVICE_TYPE_CONTROLLER; 145 mChannel = params.getChannelNumber(); 146 mRangingIntervalMs = params.getRangingIntervalMs(); 147 } 148 parseCccParams(CccOpenRangingParams params)149 private void parseCccParams(CccOpenRangingParams params) { 150 mChannel = params.getChannel(); 151 } 152 convertInitStatus(int status)153 private void convertInitStatus(int status) { 154 mInitStatus = UwbStatsLog.UWB_SESSION_INITIATED__STATUS__GENERAL_FAILURE; 155 switch (status) { 156 case UwbUciConstants.STATUS_CODE_OK: 157 mInitStatus = UwbStatsLog.UWB_SESSION_INITIATED__STATUS__SUCCESS; 158 break; 159 case UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED: 160 mInitStatus = UwbStatsLog.UWB_SESSION_INITIATED__STATUS__SESSION_EXCEEDED; 161 break; 162 case UwbUciConstants.STATUS_CODE_ERROR_SESSION_DUPLICATE: 163 mInitStatus = UwbStatsLog.UWB_SESSION_INITIATED__STATUS__SESSION_DUPLICATE; 164 break; 165 case UwbUciConstants.STATUS_CODE_INVALID_PARAM: 166 case UwbUciConstants.STATUS_CODE_INVALID_RANGE: 167 case UwbUciConstants.STATUS_CODE_INVALID_MESSAGE_SIZE: 168 mInitStatus = UwbStatsLog.UWB_SESSION_INITIATED__STATUS__BAD_PARAMS; 169 break; 170 } 171 } 172 convertRangingStatus(int status)173 private void convertRangingStatus(int status) { 174 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RANGING_GENERAL_FAILURE; 175 switch (status) { 176 case UwbUciConstants.STATUS_CODE_OK: 177 case UwbUciConstants.STATUS_CODE_OK_NEGATIVE_DISTANCE_REPORT: 178 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RANGING_SUCCESS; 179 break; 180 case UwbUciConstants.STATUS_CODE_RANGING_TX_FAILED: 181 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__TX_FAILED; 182 break; 183 case UwbUciConstants.STATUS_CODE_RANGING_RX_PHY_DEC_FAILED: 184 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RX_PHY_DEC_FAILED; 185 break; 186 case UwbUciConstants.STATUS_CODE_RANGING_RX_PHY_TOA_FAILED: 187 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RX_PHY_TOA_FAILED; 188 break; 189 case UwbUciConstants.STATUS_CODE_RANGING_RX_PHY_STS_FAILED: 190 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RX_PHY_STS_FAILED; 191 break; 192 case UwbUciConstants.STATUS_CODE_RANGING_RX_MAC_DEC_FAILED: 193 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RX_MAC_DEC_FAILED; 194 break; 195 case UwbUciConstants.STATUS_CODE_RANGING_RX_MAC_IE_DEC_FAILED: 196 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RX_MAC_IE_DEC_FAILED; 197 break; 198 case UwbUciConstants.STATUS_CODE_RANGING_RX_MAC_IE_MISSING: 199 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RX_MAC_IE_MISSING; 200 break; 201 case UwbUciConstants.STATUS_CODE_INVALID_PARAM: 202 case UwbUciConstants.STATUS_CODE_INVALID_RANGE: 203 case UwbUciConstants.STATUS_CODE_INVALID_MESSAGE_SIZE: 204 mRangingStatus = UwbStatsLog.UWB_START_RANGING__STATUS__RANGING_BAD_PARAMS; 205 break; 206 } 207 } 208 209 @Override toString()210 public String toString() { 211 StringBuilder sb = new StringBuilder(); 212 sb.append("initTime="); 213 Calendar c = Calendar.getInstance(); 214 synchronized (mLock) { 215 c.setTimeInMillis(mInitTimeWallClockMs); 216 sb.append(mInitTimeWallClockMs == 0 ? " <null>" : 217 String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 218 sb.append(", sessionId=").append(mSessionId); 219 sb.append(", initLatencyMs=").append(mInitLatencyMs); 220 sb.append(", activeDurationMs=").append(mActiveDuration); 221 sb.append(", rangingCount=").append(mRangingCount); 222 sb.append(", validRangingCount=").append(mValidRangingCount); 223 sb.append(", startCount=").append(mStartCount); 224 sb.append(", startFailureCount=").append(mStartFailureCount); 225 sb.append(", startNoValidReportCount=").append(mStartNoValidReportCount); 226 sb.append(", initStatus=").append(mInitStatus); 227 sb.append(", channel=").append(mChannel); 228 sb.append(", initiator=").append(mIsInitiator); 229 sb.append(", controller=").append(mIsController); 230 sb.append(", discoveredByFramework=").append(mIsDiscoveredByFramework); 231 sb.append(", uid=").append(mAttributionSource.getUid()); 232 sb.append(", packageName=").append(mAttributionSource.getPackageName()); 233 sb.append(", rangingIntervalMs=").append(mRangingIntervalMs); 234 sb.append(", parallelSessionCount=").append(mParallelSessionCount); 235 sb.append(", rxPacketCount=").append(mRxPacketCount); 236 sb.append(", txPacketCount=").append(mTxPacketCount); 237 sb.append(", rxErrorCount=").append(mRxErrorCount); 238 sb.append(", txErrorCount=").append(mTxErrorCount); 239 sb.append(", rxToUpperLayerCount=").append(mRxToUpperLayerCount); 240 sb.append(", rangingType=").append(mRangingType); 241 return sb.toString(); 242 } 243 } 244 } 245 246 private class RangingReportEvent { 247 private int mSessionId; 248 private int mNlos; 249 private int mDistanceCm = INVALID_DISTANCE; 250 private int mAzimuthDegree; 251 private int mAzimuthFom; 252 private int mElevationDegree; 253 private int mElevationFom; 254 private int mRssiDbm = RangingMeasurement.RSSI_UNKNOWN; 255 private int mRangingType; 256 private int mFilteredDistanceCm = INVALID_DISTANCE; 257 private int mFilteredAzimuthDegree; 258 private int mFilteredAzimuthFom; 259 private int mFilteredElevationDegree; 260 private int mFilteredElevationFom; 261 private long mWallClockMillis = mUwbInjector.getWallClockMillis();; 262 private boolean mIsStatusOk; 263 RangingReportEvent(UwbTwoWayMeasurement measurement)264 RangingReportEvent(UwbTwoWayMeasurement measurement) { 265 mNlos = convertNlos(measurement.getNLoS()); 266 mDistanceCm = measurement.getDistance(); 267 mAzimuthDegree = (int) measurement.getAoaAzimuth(); 268 mAzimuthFom = measurement.getAoaAzimuthFom(); 269 mElevationDegree = (int) measurement.getAoaElevation(); 270 mElevationFom = measurement.getAoaElevationFom(); 271 mRssiDbm = measurement.getRssi(); 272 mRangingType = UwbStatsLog.UWB_RANGING_MEASUREMENT_RECEIVED__RANGING_TYPE__TWO_WAY; 273 mIsStatusOk = measurement.isStatusCodeOk(); 274 } 275 RangingReportEvent(UwbDlTDoAMeasurement measurement)276 RangingReportEvent(UwbDlTDoAMeasurement measurement) { 277 mNlos = convertNlos(measurement.getNLoS()); 278 mAzimuthDegree = (int) measurement.getAoaAzimuth(); 279 mAzimuthFom = measurement.getAoaAzimuthFom(); 280 mElevationDegree = (int) measurement.getAoaElevation(); 281 mElevationFom = measurement.getAoaElevationFom(); 282 mRssiDbm = measurement.getRssi(); 283 mRangingType = UwbStatsLog.UWB_RANGING_MEASUREMENT_RECEIVED__RANGING_TYPE__DL_TDOA; 284 mIsStatusOk = measurement.getStatus() == UwbUciConstants.STATUS_CODE_OK; 285 } 286 RangingReportEvent(UwbOwrAoaMeasurement measurement)287 RangingReportEvent(UwbOwrAoaMeasurement measurement) { 288 mNlos = convertNlos(measurement.getNLoS()); 289 mAzimuthDegree = (int) measurement.getAoaAzimuth(); 290 mAzimuthFom = measurement.getAoaAzimuthFom(); 291 mElevationDegree = (int) measurement.getAoaElevation(); 292 mElevationFom = measurement.getAoaElevationFom(); 293 mRangingType = UwbStatsLog.UWB_RANGING_MEASUREMENT_RECEIVED__RANGING_TYPE__OWR_AOA; 294 mIsStatusOk = measurement.getRangingStatus() == UwbUciConstants.STATUS_CODE_OK; 295 } 296 addFilteredResults(RangingMeasurement filteredRangingMeasurement)297 private void addFilteredResults(RangingMeasurement filteredRangingMeasurement) { 298 if (filteredRangingMeasurement == null) { 299 return; 300 } 301 if (filteredRangingMeasurement.getDistanceMeasurement() != null) { 302 mFilteredDistanceCm = (int) (filteredRangingMeasurement 303 .getDistanceMeasurement().getMeters() * 100); 304 } 305 if (filteredRangingMeasurement.getAngleOfArrivalMeasurement() != null) { 306 mFilteredAzimuthDegree = (int) Math.toDegrees(filteredRangingMeasurement 307 .getAngleOfArrivalMeasurement().getAzimuth().getRadians()); 308 mFilteredAzimuthFom = (int) (filteredRangingMeasurement 309 .getAngleOfArrivalMeasurement().getAzimuth() 310 .getConfidenceLevel() * 100); 311 mFilteredElevationDegree = (int) Math.toDegrees(filteredRangingMeasurement 312 .getAngleOfArrivalMeasurement().getAltitude().getRadians()); 313 mFilteredElevationFom = (int) (filteredRangingMeasurement 314 .getAngleOfArrivalMeasurement().getAltitude() 315 .getConfidenceLevel() * 100); 316 } 317 } 318 319 @Override toString()320 public String toString() { 321 StringBuilder sb = new StringBuilder(); 322 sb.append("time="); 323 Calendar c = Calendar.getInstance(); 324 synchronized (mLock) { 325 c.setTimeInMillis(mWallClockMillis); 326 sb.append(mWallClockMillis == 0 ? " <null>" : 327 String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 328 sb.append(", sessionId=").append(mSessionId); 329 sb.append(", Nlos=").append(mNlos); 330 sb.append(", DistanceCm=").append(mDistanceCm); 331 sb.append(", AzimuthDegree=").append(mAzimuthDegree); 332 sb.append(", AzimuthFom=").append(mAzimuthFom); 333 sb.append(", ElevationDegree=").append(mElevationDegree); 334 sb.append(", ElevationFom=").append(mElevationFom); 335 sb.append(", RssiDbm=").append(mRssiDbm); 336 sb.append(", FilteredDistanceCm=").append(mFilteredDistanceCm); 337 sb.append(", FilteredAzimuthDegree=").append(mFilteredAzimuthDegree); 338 sb.append(", FilteredAzimuthFom=").append(mFilteredAzimuthFom); 339 sb.append(", FilteredElevationDegree=").append(mFilteredElevationDegree); 340 sb.append(", FilteredElevationFom=").append(mFilteredElevationFom); 341 sb.append(", RangingType=").append(mRangingType); 342 return sb.toString(); 343 } 344 } 345 } 346 UwbMetrics(UwbInjector uwbInjector)347 public UwbMetrics(UwbInjector uwbInjector) { 348 mUwbInjector = uwbInjector; 349 } 350 351 /** 352 * Log the ranging session initialization event 353 */ logRangingInitEvent(UwbSession uwbSession, int status)354 public void logRangingInitEvent(UwbSession uwbSession, int status) { 355 synchronized (mLock) { 356 // If past maximum events, start removing the oldest 357 while (mRangingSessionList.size() >= MAX_RANGING_SESSIONS) { 358 mRangingSessionList.removeFirst(); 359 } 360 RangingSessionStats session = new RangingSessionStats(uwbSession.getSessionId(), 361 uwbSession.getAttributionSource(), uwbSession.getParallelSessionCount()); 362 session.parseParams(uwbSession.getParams()); 363 session.convertInitStatus(status); 364 mRangingSessionList.add(session); 365 mOpenedSessionMap.put(uwbSession.getSessionId(), session); 366 if (status != UwbUciConstants.STATUS_CODE_OK) { 367 takBugReportSessionInitError("UWB Bugreport: session init failed reason " + status); 368 } 369 UwbStatsLog.write(UwbStatsLog.UWB_SESSION_INITED, uwbSession.getProfileType(), 370 session.mStsType, session.mIsInitiator, 371 session.mIsController, session.mIsDiscoveredByFramework, session.mIsOutOfBand, 372 session.mChannel, session.mInitStatus, 373 session.mInitLatencyMs, session.mInitLatencyMs / 20, 374 uwbSession.getAttributionSource().getUid(), session.mRangingIntervalMs, 375 session.mParallelSessionCount, session.mFilterConfigValue 376 ); 377 } 378 } 379 380 /** 381 * Log the ranging session start event 382 */ longRangingStartEvent(UwbSession uwbSession, int status)383 public void longRangingStartEvent(UwbSession uwbSession, int status) { 384 synchronized (mLock) { 385 RangingSessionStats session = mOpenedSessionMap.get(uwbSession.getSessionId()); 386 if (session == null) { 387 return; 388 } 389 session.mStartCount++; 390 session.convertRangingStatus(status); 391 UwbStatsLog.write(UwbStatsLog.UWB_RANGING_START, uwbSession.getProfileType(), 392 session.mStsType, session.mIsInitiator, 393 session.mIsController, session.mIsDiscoveredByFramework, session.mIsOutOfBand, 394 session.mRangingStatus); 395 if (status != UwbUciConstants.STATUS_CODE_OK) { 396 session.mStartFailureCount++; 397 session.mStartTimeSinceBootMs = 0; 398 session.mHasValidRangingSinceStart = false; 399 return; 400 } 401 session.mStartTimeSinceBootMs = mUwbInjector.getElapsedSinceBootMillis(); 402 } 403 } 404 takBugReportSessionInitError(String bugTitle)405 private void takBugReportSessionInitError(String bugTitle) { 406 if (mUwbInjector.getDeviceConfigFacade().isSessionInitErrorBugreportEnabled()) { 407 mUwbInjector.getUwbDiagnostics().takeBugReport(bugTitle); 408 } 409 } 410 411 /** 412 * Log the ranging session stop event 413 */ longRangingStopEvent(UwbSession uwbSession)414 public void longRangingStopEvent(UwbSession uwbSession) { 415 synchronized (mLock) { 416 RangingSessionStats session = mOpenedSessionMap.get(uwbSession.getSessionId()); 417 if (session == null) { 418 return; 419 } 420 if (session.mStartTimeSinceBootMs == 0) { 421 return; 422 } 423 if (!session.mHasValidRangingSinceStart) { 424 session.mStartNoValidReportCount++; 425 } 426 session.mHasValidRangingSinceStart = false; 427 session.mActiveDuration += (int) (mUwbInjector.getElapsedSinceBootMillis() 428 - session.mStartTimeSinceBootMs); 429 session.mStartTimeSinceBootMs = 0; 430 } 431 } 432 433 /** 434 * Log the ranging session close event 435 */ logRangingCloseEvent(UwbSession uwbSession, int status)436 public void logRangingCloseEvent(UwbSession uwbSession, int status) { 437 synchronized (mLock) { 438 RangingSessionStats session = mOpenedSessionMap.get(uwbSession.getSessionId()); 439 if (session == null) { 440 return; 441 } 442 if (status != UwbUciConstants.STATUS_CODE_OK) { 443 return; 444 } 445 // Ranging may close without stop event 446 if (session.mStartTimeSinceBootMs != 0) { 447 session.mActiveDuration += (int) (mUwbInjector.getElapsedSinceBootMillis() 448 - session.mStartTimeSinceBootMs); 449 if (!session.mHasValidRangingSinceStart) { 450 session.mStartNoValidReportCount++; 451 } 452 session.mStartTimeSinceBootMs = 0; 453 session.mHasValidRangingSinceStart = false; 454 } 455 456 UwbStatsLog.write(UwbStatsLog.UWB_SESSION_CLOSED, uwbSession.getProfileType(), 457 session.mStsType, session.mIsInitiator, 458 session.mIsController, session.mIsDiscoveredByFramework, session.mIsOutOfBand, 459 session.mActiveDuration, getDurationBucket(session.mActiveDuration), 460 session.mRangingCount, session.mValidRangingCount, 461 getCountBucket(session.mRangingCount), 462 getCountBucket(session.mValidRangingCount), 463 session.mStartCount, 464 session.mStartFailureCount, 465 session.mStartNoValidReportCount, 466 session.mRxPacketCount, session.mTxPacketCount, session.mRxErrorCount, 467 session.mTxErrorCount, session.mRxToUpperLayerCount, session.mRangingType); 468 mOpenedSessionMap.delete(uwbSession.getSessionId()); 469 } 470 } 471 getDurationBucket(int durationMs)472 private int getDurationBucket(int durationMs) { 473 if (durationMs <= ONE_SECOND_IN_MS) { 474 return UwbStatsLog.UWB_SESSION_CLOSED__DURATION_BUCKET__WITHIN_ONE_SEC; 475 } else if (durationMs <= TEN_SECOND_IN_MS) { 476 return UwbStatsLog.UWB_SESSION_CLOSED__DURATION_BUCKET__ONE_TO_TEN_SEC; 477 } else if (durationMs <= ONE_MIN_IN_MS) { 478 return UwbStatsLog.UWB_SESSION_CLOSED__DURATION_BUCKET__TEN_SEC_TO_ONE_MIN; 479 } else if (durationMs <= TEN_MIN_IN_MS) { 480 return UwbStatsLog.UWB_SESSION_CLOSED__DURATION_BUCKET__ONE_TO_TEN_MIN; 481 } else if (durationMs <= ONE_HOUR_IN_MS) { 482 return UwbStatsLog.UWB_SESSION_CLOSED__DURATION_BUCKET__TEN_MIN_TO_ONE_HOUR; 483 } else { 484 return UwbStatsLog.UWB_SESSION_CLOSED__DURATION_BUCKET__MORE_THAN_ONE_HOUR; 485 } 486 } 487 getCountBucket(int count)488 private int getCountBucket(int count) { 489 if (count <= 0) { 490 return UwbStatsLog.UWB_SESSION_CLOSED__RANGING_COUNT_BUCKET__ZERO; 491 } else if (count <= 5) { 492 return UwbStatsLog.UWB_SESSION_CLOSED__RANGING_COUNT_BUCKET__ONE_TO_FIVE; 493 } else if (count <= 20) { 494 return UwbStatsLog.UWB_SESSION_CLOSED__RANGING_COUNT_BUCKET__FIVE_TO_TWENTY; 495 } else if (count <= 100) { 496 return UwbStatsLog.UWB_SESSION_CLOSED__RANGING_COUNT_BUCKET__TWENTY_TO_ONE_HUNDRED; 497 } else if (count <= 500) { 498 return UwbStatsLog 499 .UWB_SESSION_CLOSED__RANGING_COUNT_BUCKET__ONE_HUNDRED_TO_FIVE_HUNDRED; 500 } else { 501 return UwbStatsLog.UWB_SESSION_CLOSED__RANGING_COUNT_BUCKET__MORE_THAN_FIVE_HUNDRED; 502 } 503 } 504 505 /** 506 * Log the usage of API from a new App 507 */ logNewAppUsage()508 public void logNewAppUsage() { 509 synchronized (mLock) { 510 mNumApps++; 511 } 512 } 513 514 /** 515 * Log the ranging measurement result 516 */ logRangingResult(int profileType, UwbRangingData rawRangingData, RangingMeasurement filteredRangingMeasurement)517 public void logRangingResult(int profileType, UwbRangingData rawRangingData, 518 RangingMeasurement filteredRangingMeasurement) { 519 synchronized (mLock) { 520 int rangingMeasuresType = rawRangingData.getRangingMeasuresType(); 521 if (!SUPPORTED_RANGING_MEASUREMENT_TYPES.contains(rangingMeasuresType) 522 || rawRangingData.getNoOfRangingMeasures() < 1) { 523 return; 524 } 525 526 int sessionId = (int) rawRangingData.getSessionId(); 527 RangingSessionStats session = mOpenedSessionMap.get(sessionId); 528 if (session == null) { 529 return; 530 } 531 session.mRangingCount++; 532 533 RangingReportEvent report = getRangingReport(rangingMeasuresType, rawRangingData); 534 if (report == null) { 535 return; 536 } 537 report.mSessionId = sessionId; 538 session.mRangingType = report.mRangingType; 539 540 if (!report.mIsStatusOk) { 541 return; 542 } 543 report.addFilteredResults(filteredRangingMeasurement); 544 545 session.mValidRangingCount++; 546 if (!session.mHasValidRangingSinceStart) { 547 session.mHasValidRangingSinceStart = true; 548 writeFirstValidRangingResultSinceStart(profileType, session); 549 } 550 551 while (mRangingReportList.size() >= MAX_RANGING_REPORTS) { 552 mRangingReportList.removeFirst(); 553 } 554 mRangingReportList.add(report); 555 556 long currTimeMs = mUwbInjector.getElapsedSinceBootMillis(); 557 if ((currTimeMs - mLastRangingDataLogTimeMs) < mUwbInjector.getDeviceConfigFacade() 558 .getRangingResultLogIntervalMs()) { 559 return; 560 } 561 mLastRangingDataLogTimeMs = currTimeMs; 562 563 boolean isDistanceValid = report.mDistanceCm != INVALID_DISTANCE; 564 boolean isAzimuthValid = report.mAzimuthFom > 0; 565 boolean isElevationValid = report.mElevationFom > 0; 566 int distance50Cm = isDistanceValid ? report.mDistanceCm / 50 : 0; 567 int azimuth10Degree = isAzimuthValid ? report.mAzimuthDegree / 10 : 0; 568 int elevation10Degree = isElevationValid ? report.mElevationDegree / 10 : 0; 569 UwbStatsLog.write(UwbStatsLog.UWB_RANGING_MEASUREMENT_RECEIVED, 570 profileType, report.mNlos, 571 isDistanceValid, report.mDistanceCm, distance50Cm, report.mRssiDbm, 572 isAzimuthValid, report.mAzimuthDegree, azimuth10Degree, report.mAzimuthFom, 573 isElevationValid, report.mElevationDegree, elevation10Degree, 574 report.mElevationFom, session.mRangingType, report.mFilteredDistanceCm, 575 report.mFilteredAzimuthDegree, report.mFilteredAzimuthFom, 576 report.mFilteredElevationDegree, report.mFilteredElevationFom); 577 } 578 } 579 writeFirstValidRangingResultSinceStart(int profileType, RangingSessionStats session)580 private void writeFirstValidRangingResultSinceStart(int profileType, 581 RangingSessionStats session) { 582 int latencyMs = (int) (mUwbInjector.getElapsedSinceBootMillis() 583 - session.mStartTimeSinceBootMs); 584 UwbStatsLog.write(UwbStatsLog.UWB_FIRST_RANGING_RECEIVED, 585 profileType, latencyMs, latencyMs / 200); 586 } 587 convertNlos(int nlos)588 private int convertNlos(int nlos) { 589 if (nlos == 0) { 590 return UwbStatsLog.UWB_RANGING_MEASUREMENT_RECEIVED__NLOS__LOS; 591 } else if (nlos == 1) { 592 return UwbStatsLog.UWB_RANGING_MEASUREMENT_RECEIVED__NLOS__NLOS; 593 } else { 594 return UwbStatsLog.UWB_RANGING_MEASUREMENT_RECEIVED__NLOS__NLOS_UNKNOWN; 595 } 596 } 597 getRangingReport(int rangingType, UwbRangingData rangingData)598 private RangingReportEvent getRangingReport(int rangingType, UwbRangingData rangingData) { 599 switch (rangingType) { 600 case UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY: 601 UwbTwoWayMeasurement[] uwbTwoWayMeasurements = 602 rangingData.getRangingTwoWayMeasures(); 603 return new RangingReportEvent(uwbTwoWayMeasurements[0]); 604 case UwbUciConstants.RANGING_MEASUREMENT_TYPE_DL_TDOA: 605 UwbDlTDoAMeasurement[] uwbDlTDoAMeasurements = 606 rangingData.getUwbDlTDoAMeasurements(); 607 return new RangingReportEvent(uwbDlTDoAMeasurements[0]); 608 case UwbUciConstants.RANGING_MEASUREMENT_TYPE_OWR_AOA: 609 return new RangingReportEvent(rangingData.getRangingOwrAoaMeasure()); 610 default: 611 return null; 612 } 613 } 614 615 /** 616 * Log Rx data packet count 617 */ logDataRx(UwbSession uwbSession, int status)618 public synchronized void logDataRx(UwbSession uwbSession, int status) { 619 synchronized (mLock) { 620 RangingSessionStats session = mOpenedSessionMap.get(uwbSession.getSessionId()); 621 if (session == null) { 622 return; 623 } 624 if (status == UwbUciConstants.STATUS_CODE_OK) { 625 session.mRxPacketCount++; 626 } else { 627 session.mRxErrorCount++; 628 } 629 } 630 } 631 632 /** 633 * Log Tx data packet count 634 */ logDataTx(UwbSession uwbSession, int status)635 public synchronized void logDataTx(UwbSession uwbSession, int status) { 636 synchronized (mLock) { 637 RangingSessionStats session = mOpenedSessionMap.get(uwbSession.getSessionId()); 638 if (session == null) { 639 return; 640 } 641 if (status == UwbUciConstants.STATUS_CODE_OK) { 642 session.mTxPacketCount++; 643 } else { 644 session.mTxErrorCount++; 645 } 646 } 647 } 648 649 /** 650 * Log count of Rx data packets sent to upper layer 651 */ logDataToUpperLayer(UwbSession uwbSession, int packetCount)652 public synchronized void logDataToUpperLayer(UwbSession uwbSession, int packetCount) { 653 synchronized (mLock) { 654 RangingSessionStats session = mOpenedSessionMap.get(uwbSession.getSessionId()); 655 if (session == null) { 656 return; 657 } 658 session.mRxToUpperLayerCount += packetCount; 659 } 660 } 661 662 private int mNumDeviceInitSuccess = 0; 663 private int mNumDeviceInitFailure = 0; 664 private int mNumDeviceStatusError = 0; 665 private int mNumUciGenericError = 0; 666 667 /** 668 * Increment the count of device initialization success 669 */ incrementDeviceInitSuccessCount()670 public synchronized void incrementDeviceInitSuccessCount() { 671 mNumDeviceInitSuccess++; 672 } 673 674 /** 675 * Increment the count of device initialization failure 676 */ incrementDeviceInitFailureCount()677 public synchronized void incrementDeviceInitFailureCount() { 678 mNumDeviceInitFailure++; 679 UwbStatsLog.write(UwbStatsLog.UWB_DEVICE_ERROR_REPORTED, 680 UwbStatsLog.UWB_DEVICE_ERROR_REPORTED__TYPE__INIT_ERROR); 681 } 682 683 /** 684 * Increment the count of device status error 685 */ incrementDeviceStatusErrorCount()686 public synchronized void incrementDeviceStatusErrorCount() { 687 mNumDeviceStatusError++; 688 UwbStatsLog.write(UwbStatsLog.UWB_DEVICE_ERROR_REPORTED, 689 UwbStatsLog.UWB_DEVICE_ERROR_REPORTED__TYPE__DEVICE_STATUS_ERROR); 690 } 691 692 /** 693 * Increment the count of UCI generic error which will trigger UCI command retry 694 */ incrementUciGenericErrorCount()695 public synchronized void incrementUciGenericErrorCount() { 696 mNumUciGenericError++; 697 UwbStatsLog.write(UwbStatsLog.UWB_DEVICE_ERROR_REPORTED, 698 UwbStatsLog.UWB_DEVICE_ERROR_REPORTED__TYPE__UCI_GENERIC_ERROR); 699 } 700 701 /** 702 * Dump the UWB logs 703 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)704 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 705 synchronized (mLock) { 706 pw.println("---- Dump of UwbMetrics ----"); 707 pw.println("-- mRangingSessionList --"); 708 for (RangingSessionStats stats: mRangingSessionList) { 709 pw.println(stats.toString()); 710 } 711 pw.println("-- mOpenedSessionMap --"); 712 for (int i = 0; i < mOpenedSessionMap.size(); i++) { 713 pw.println(mOpenedSessionMap.valueAt(i).toString()); 714 } 715 pw.println("-- mRangingReportList --"); 716 for (RangingReportEvent event: mRangingReportList) { 717 pw.println(event.toString()); 718 } 719 pw.println("mNumApps=" + mNumApps); 720 pw.println("-- Device operation success/error count --"); 721 pw.println("mNumDeviceInitSuccess = " + mNumDeviceInitSuccess); 722 pw.println("mNumDeviceInitFailure = " + mNumDeviceInitFailure); 723 pw.println("mNumDeviceStatusError = " + mNumDeviceStatusError); 724 pw.println("mNumUciGenericError = " + mNumUciGenericError); 725 pw.println("---- Dump of UwbMetrics ----"); 726 } 727 } 728 } 729