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