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