• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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