1 /* 2 * Copyright (C) 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.telecom.metrics; 18 19 import static com.android.server.telecom.TelecomStatsLog.TELECOM_EVENT_STATS; 20 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.app.StatsManager; 24 import android.content.Context; 25 import android.os.Looper; 26 import android.telecom.CallException; 27 import android.telecom.Log; 28 import android.util.StatsEvent; 29 30 import androidx.annotation.VisibleForTesting; 31 32 import com.android.server.telecom.TelecomStatsLog; 33 import com.android.server.telecom.metrics.ApiStats.ApiEvent; 34 import com.android.server.telecom.nano.PulledAtomsClass; 35 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.util.Arrays; 39 import java.util.HashMap; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.Objects; 43 44 public class EventStats extends TelecomPulledAtom { 45 public static final int ID_UNKNOWN = TelecomStatsLog.TELECOM_EVENT_STATS__EVENT__EVENT_UNKNOWN; 46 public static final int ID_INIT = TelecomStatsLog.TELECOM_EVENT_STATS__EVENT__EVENT_INIT; 47 public static final int ID_DEFAULT_DIALER_CHANGED = TelecomStatsLog 48 .TELECOM_EVENT_STATS__EVENT__EVENT_DEFAULT_DIALER_CHANGED; 49 public static final int ID_ADD_CALL = TelecomStatsLog 50 .TELECOM_EVENT_STATS__EVENT__EVENT_ADD_CALL; 51 52 public static final int CAUSE_UNKNOWN = TelecomStatsLog 53 .TELECOM_EVENT_STATS__EVENT_CAUSE__CAUSE_UNKNOWN; 54 public static final int CAUSE_GENERIC_SUCCESS = TelecomStatsLog 55 .TELECOM_EVENT_STATS__EVENT_CAUSE__CAUSE_GENERIC_SUCCESS; 56 public static final int CAUSE_GENERIC_FAILURE = TelecomStatsLog 57 .TELECOM_EVENT_STATS__EVENT_CAUSE__CAUSE_GENERIC_FAILURE; 58 public static final int CAUSE_CALL_TRANSACTION_SUCCESS = TelecomStatsLog 59 .TELECOM_EVENT_STATS__EVENT_CAUSE__CALL_TRANSACTION_SUCCESS; 60 public static final int CAUSE_CALL_TRANSACTION_BASE = CAUSE_CALL_TRANSACTION_SUCCESS; 61 public static final int CAUSE_CALL_TRANSACTION_ERROR_UNKNOWN = 62 CAUSE_CALL_TRANSACTION_BASE + CallException.CODE_ERROR_UNKNOWN; 63 public static final int CAUSE_CALL_TRANSACTION_CANNOT_HOLD_CURRENT_ACTIVE_CALL = 64 CAUSE_CALL_TRANSACTION_BASE + CallException.CODE_CANNOT_HOLD_CURRENT_ACTIVE_CALL; 65 public static final int CAUSE_CALL_TRANSACTION_CALL_IS_NOT_BEING_TRACKED = 66 CAUSE_CALL_TRANSACTION_BASE + CallException.CODE_CALL_IS_NOT_BEING_TRACKED; 67 public static final int CAUSE_CALL_TRANSACTION_CALL_CANNOT_BE_SET_TO_ACTIVE = 68 CAUSE_CALL_TRANSACTION_BASE + CallException.CODE_CALL_CANNOT_BE_SET_TO_ACTIVE; 69 public static final int CAUSE_CALL_TRANSACTION_CALL_NOT_PERMITTED_AT_PRESENT_TIME = 70 CAUSE_CALL_TRANSACTION_BASE + CallException.CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME; 71 public static final int CAUSE_CALL_TRANSACTION_OPERATION_TIMED_OUT = 72 CAUSE_CALL_TRANSACTION_BASE + CallException.CODE_OPERATION_TIMED_OUT; 73 private static final String TAG = EventStats.class.getSimpleName(); 74 private static final String FILE_NAME = "event_stats"; 75 private Map<CriticalEvent, Integer> mEventStatsMap; 76 EventStats(@onNull Context context, @NonNull Looper looper, boolean isTestMode)77 public EventStats(@NonNull Context context, @NonNull Looper looper, 78 boolean isTestMode) { 79 super(context, looper, isTestMode); 80 } 81 82 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 83 @Override getTag()84 public int getTag() { 85 return TELECOM_EVENT_STATS; 86 } 87 88 @Override getFileName()89 protected String getFileName() { 90 return FILE_NAME; 91 } 92 93 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 94 @Override onPull(final List<StatsEvent> data)95 public synchronized int onPull(final List<StatsEvent> data) { 96 if (mPulledAtoms.telecomEventStats.length != 0) { 97 Arrays.stream(mPulledAtoms.telecomEventStats).forEach(v -> data.add( 98 TelecomStatsLog.buildStatsEvent(getTag(), 99 v.getEvent(), v.getUid(), v.getEventCause(), v.getCount()))); 100 mEventStatsMap.clear(); 101 onAggregate(); 102 return StatsManager.PULL_SUCCESS; 103 } else { 104 return StatsManager.PULL_SKIP; 105 } 106 } 107 108 @Override onLoad()109 protected synchronized void onLoad() { 110 if (mPulledAtoms.telecomEventStats != null) { 111 mEventStatsMap = new HashMap<>(); 112 for (PulledAtomsClass.TelecomEventStats v : mPulledAtoms.telecomEventStats) { 113 mEventStatsMap.put(new CriticalEvent(v.getEvent(), v.getUid(), 114 v.getEventCause()), v.getCount()); 115 } 116 mLastPulledTimestamps = mPulledAtoms.getTelecomEventStatsPullTimestampMillis(); 117 } 118 } 119 120 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 121 @Override onAggregate()122 public synchronized void onAggregate() { 123 Log.d(TAG, "onAggregate: %s", mEventStatsMap); 124 clearAtoms(); 125 if (mEventStatsMap.isEmpty()) { 126 return; 127 } 128 mPulledAtoms.setTelecomEventStatsPullTimestampMillis(mLastPulledTimestamps); 129 mPulledAtoms.telecomEventStats = 130 new PulledAtomsClass.TelecomEventStats[mEventStatsMap.size()]; 131 int[] index = new int[1]; 132 mEventStatsMap.forEach((k, v) -> { 133 mPulledAtoms.telecomEventStats[index[0]] = new PulledAtomsClass.TelecomEventStats(); 134 mPulledAtoms.telecomEventStats[index[0]].setEvent(k.mId); 135 mPulledAtoms.telecomEventStats[index[0]].setUid(k.mUid); 136 mPulledAtoms.telecomEventStats[index[0]].setEventCause(k.mCause); 137 mPulledAtoms.telecomEventStats[index[0]].setCount(v); 138 index[0]++; 139 }); 140 save(DELAY_FOR_PERSISTENT_MILLIS); 141 } 142 log(@onNull CriticalEvent event)143 public void log(@NonNull CriticalEvent event) { 144 post(() -> { 145 mEventStatsMap.put(event, mEventStatsMap.getOrDefault(event, 0) + 1); 146 onAggregate(); 147 }); 148 } 149 150 @IntDef(prefix = "ID_", value = { 151 ID_UNKNOWN, 152 ID_INIT, 153 ID_DEFAULT_DIALER_CHANGED, 154 ID_ADD_CALL 155 }) 156 @Retention(RetentionPolicy.SOURCE) 157 public @interface EventId { 158 } 159 160 @IntDef(prefix = "CAUSE_", value = { 161 CAUSE_UNKNOWN, 162 CAUSE_GENERIC_SUCCESS, 163 CAUSE_GENERIC_FAILURE, 164 CAUSE_CALL_TRANSACTION_SUCCESS, 165 CAUSE_CALL_TRANSACTION_ERROR_UNKNOWN, 166 CAUSE_CALL_TRANSACTION_CANNOT_HOLD_CURRENT_ACTIVE_CALL, 167 CAUSE_CALL_TRANSACTION_CALL_IS_NOT_BEING_TRACKED, 168 CAUSE_CALL_TRANSACTION_CALL_CANNOT_BE_SET_TO_ACTIVE, 169 CAUSE_CALL_TRANSACTION_CALL_NOT_PERMITTED_AT_PRESENT_TIME, 170 CAUSE_CALL_TRANSACTION_OPERATION_TIMED_OUT 171 }) 172 @Retention(RetentionPolicy.SOURCE) 173 public @interface CauseId { 174 } 175 176 public static class CriticalEvent { 177 178 @EventId 179 int mId; 180 int mUid; 181 @CauseId 182 int mCause; 183 CriticalEvent(@ventId int id, int uid, @CauseId int cause)184 public CriticalEvent(@EventId int id, int uid, @CauseId int cause) { 185 mId = id; 186 mUid = uid; 187 mCause = cause; 188 } 189 setUid(int uid)190 public void setUid(int uid) { 191 this.mUid = uid; 192 } 193 setResult(@auseId int result)194 public void setResult(@CauseId int result) { 195 this.mCause = result; 196 } 197 198 @Override equals(Object other)199 public boolean equals(Object other) { 200 if (this == other) { 201 return true; 202 } 203 if (!(other instanceof ApiEvent obj)) { 204 return false; 205 } 206 return this.mId == obj.mId && this.mUid == obj.mCallerUid 207 && this.mCause == obj.mResult; 208 } 209 210 @Override hashCode()211 public int hashCode() { 212 return Objects.hash(mId, mUid, mCause); 213 } 214 215 @Override toString()216 public String toString() { 217 return "[CriticalEvent: mId=" + mId + ", m" 218 + "Uid=" + mUid 219 + ", mResult=" + mCause + "]"; 220 } 221 } 222 223 224 } 225