1 /* 2 * Copyright 2025 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 17 package com.android.server.ranging.metrics; 18 19 import static android.ranging.RangingConfig.RANGING_SESSION_RAW; 20 21 import android.content.AttributionSource; 22 import android.ranging.RangingConfig; 23 import android.ranging.RangingPreference; 24 import android.ranging.SessionHandle; 25 26 import com.android.server.ranging.RangingInjector; 27 import com.android.server.ranging.RangingTechnology; 28 import com.android.server.ranging.RangingUtils.InternalReason; 29 import com.android.server.ranging.RangingUtils.StateMachine; 30 31 public class SessionMetricsLogger { 32 private final SessionHandle mSessionHandle; 33 private final @RangingPreference.DeviceRole int mDeviceRole; 34 private final @RangingConfig.RangingSessionType int mSessionType; 35 private final StateMachine<State> mStateMachine; 36 private final AttributionSource mAttributionSource; 37 private final RangingInjector mInjector; 38 39 private long mLastStateChangeTimestampMs; 40 startLogging( SessionHandle sessionHandle, @RangingPreference.DeviceRole int deviceRole, @RangingConfig.RangingSessionType int sessionType, AttributionSource attributionSource, RangingInjector injector )41 public static SessionMetricsLogger startLogging( 42 SessionHandle sessionHandle, 43 @RangingPreference.DeviceRole int deviceRole, 44 @RangingConfig.RangingSessionType int sessionType, 45 AttributionSource attributionSource, 46 RangingInjector injector 47 ) { 48 return new SessionMetricsLogger(sessionHandle, deviceRole, sessionType, attributionSource, 49 injector); 50 } 51 SessionMetricsLogger( SessionHandle sessionHandle, @RangingPreference.DeviceRole int deviceRole, @RangingConfig.RangingSessionType int sessionType, AttributionSource attributionSource, RangingInjector injector )52 private SessionMetricsLogger( 53 SessionHandle sessionHandle, 54 @RangingPreference.DeviceRole int deviceRole, 55 @RangingConfig.RangingSessionType int sessionType, 56 AttributionSource attributionSource, 57 RangingInjector injector 58 ) { 59 mSessionHandle = sessionHandle; 60 mDeviceRole = deviceRole; 61 mSessionType = sessionType; 62 mStateMachine = new StateMachine<>( 63 sessionType == RANGING_SESSION_RAW 64 ? State.STARTING 65 : State.OOB); 66 mLastStateChangeTimestampMs = System.currentTimeMillis(); 67 mAttributionSource = attributionSource; 68 mInjector = injector; 69 } 70 logSessionConfigured(int numPeers)71 public synchronized void logSessionConfigured(int numPeers) { 72 RangingStatsLog.write( 73 RangingStatsLog.RANGING_SESSION_CONFIGURED, 74 mSessionHandle.hashCode(), 75 mStateMachine.getState() == State.OOB 76 ? System.currentTimeMillis() - mLastStateChangeTimestampMs 77 : 0, 78 coerceUnknownEnumValueToZero(mSessionType, 2), 79 coerceUnknownEnumValueToZero(mDeviceRole, 2), 80 numPeers, 81 mAttributionSource.getUid()); 82 mLastStateChangeTimestampMs = System.currentTimeMillis(); 83 mStateMachine.setState(State.STARTING); 84 } 85 logSessionStarted()86 public synchronized void logSessionStarted() { 87 RangingStatsLog.write( 88 RangingStatsLog.RANGING_SESSION_STARTED, 89 mSessionHandle.hashCode(), 90 mAttributionSource.getUid(), 91 System.currentTimeMillis() - mLastStateChangeTimestampMs, 92 mInjector.isPrivilegedApp( 93 mAttributionSource.getUid(), 94 mAttributionSource.getPackageName())); 95 mLastStateChangeTimestampMs = System.currentTimeMillis(); 96 mStateMachine.setState(State.RANGING); 97 } 98 logTechnologyStarted(RangingTechnology technology, int numPeers)99 public synchronized void logTechnologyStarted(RangingTechnology technology, int numPeers) { 100 RangingStatsLog.write( 101 RangingStatsLog.RANGING_TECHNOLOGY_STARTED, 102 mSessionHandle.hashCode(), 103 coerceUnknownEnumValueToZero( 104 technology.getValue(), RangingTechnology.TECHNOLOGIES.size()), 105 numPeers, 106 mAttributionSource.getUid()); 107 } 108 logTechnologyStopped( RangingTechnology technology, int numPeers, @InternalReason int reason )109 public synchronized void logTechnologyStopped( 110 RangingTechnology technology, int numPeers, @InternalReason int reason 111 ) { 112 RangingStatsLog.write( 113 RangingStatsLog.RANGING_TECHNOLOGY_STOPPED, 114 mSessionHandle.hashCode(), 115 coerceUnknownEnumValueToZero( 116 technology.getValue(), RangingTechnology.TECHNOLOGIES.size()), 117 coerceUnknownEnumValueToZero( 118 mStateMachine.getState().toInt(), State.values().length), 119 reason, 120 numPeers, 121 mAttributionSource.getUid()); 122 } 123 logSessionClosed(@nternalReason int reason)124 public synchronized void logSessionClosed(@InternalReason int reason) { 125 RangingStatsLog.write( 126 RangingStatsLog.RANGING_SESSION_CLOSED, 127 mSessionHandle.hashCode(), 128 coerceUnknownEnumValueToZero( 129 mStateMachine.getState().toInt(), State.values().length), 130 System.currentTimeMillis() - mLastStateChangeTimestampMs, 131 reason, 132 mAttributionSource.getUid()); 133 mLastStateChangeTimestampMs = System.currentTimeMillis(); 134 } 135 coerceUnknownEnumValueToZero(int enumValue, int numEnumValues)136 private int coerceUnknownEnumValueToZero(int enumValue, int numEnumValues) { 137 if (enumValue >= numEnumValues) { 138 return 0; 139 } else { 140 return enumValue + 1; 141 } 142 } 143 144 private enum State { 145 OOB(0), 146 STARTING(1), 147 RANGING(2); 148 149 private final int mValue; 150 State(int value)151 State(int value) { 152 mValue = value; 153 } 154 toInt()155 public final int toInt() { 156 return mValue; 157 } 158 } 159 } 160