1 /* 2 * Copyright (C) 2024 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_ERROR_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.Log; 27 import android.util.StatsEvent; 28 29 import androidx.annotation.VisibleForTesting; 30 31 import com.android.server.telecom.TelecomStatsLog; 32 import com.android.server.telecom.nano.PulledAtomsClass; 33 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.util.Arrays; 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.Objects; 41 42 public class ErrorStats extends TelecomPulledAtom { 43 public static final int SUB_UNKNOWN = TelecomStatsLog 44 .TELECOM_ERROR_STATS__SUBMODULE__SUB_UNKNOWN; 45 public static final int SUB_CALL_AUDIO = TelecomStatsLog 46 .TELECOM_ERROR_STATS__SUBMODULE__SUB_CALL_AUDIO; 47 public static final int SUB_CALL_LOGS = TelecomStatsLog 48 .TELECOM_ERROR_STATS__SUBMODULE__SUB_CALL_LOGS; 49 public static final int SUB_CALL_MANAGER = TelecomStatsLog 50 .TELECOM_ERROR_STATS__SUBMODULE__SUB_CALL_MANAGER; 51 public static final int SUB_CONNECTION_SERVICE = TelecomStatsLog 52 .TELECOM_ERROR_STATS__SUBMODULE__SUB_CONNECTION_SERVICE; 53 public static final int SUB_EMERGENCY_CALL = TelecomStatsLog 54 .TELECOM_ERROR_STATS__SUBMODULE__SUB_EMERGENCY_CALL; 55 public static final int SUB_IN_CALL_SERVICE = TelecomStatsLog 56 .TELECOM_ERROR_STATS__SUBMODULE__SUB_IN_CALL_SERVICE; 57 public static final int SUB_MISC = TelecomStatsLog.TELECOM_ERROR_STATS__SUBMODULE__SUB_MISC; 58 public static final int SUB_PHONE_ACCOUNT = TelecomStatsLog 59 .TELECOM_ERROR_STATS__SUBMODULE__SUB_PHONE_ACCOUNT; 60 public static final int SUB_SYSTEM_SERVICE = TelecomStatsLog 61 .TELECOM_ERROR_STATS__SUBMODULE__SUB_SYSTEM_SERVICE; 62 public static final int SUB_TELEPHONY = TelecomStatsLog 63 .TELECOM_ERROR_STATS__SUBMODULE__SUB_TELEPHONY; 64 public static final int SUB_UI = TelecomStatsLog.TELECOM_ERROR_STATS__SUBMODULE__SUB_UI; 65 public static final int SUB_VOIP_CALL = TelecomStatsLog 66 .TELECOM_ERROR_STATS__SUBMODULE__SUB_VOIP_CALL; 67 public static final int ERROR_UNKNOWN = TelecomStatsLog 68 .TELECOM_ERROR_STATS__ERROR__ERROR_UNKNOWN; 69 public static final int ERROR_EXTERNAL_EXCEPTION = TelecomStatsLog 70 .TELECOM_ERROR_STATS__ERROR__ERROR_EXTERNAL_EXCEPTION; 71 public static final int ERROR_INTERNAL_EXCEPTION = TelecomStatsLog 72 .TELECOM_ERROR_STATS__ERROR__ERROR_INTERNAL_EXCEPTION; 73 public static final int ERROR_AUDIO_ROUTE_RETRY_REJECTED = TelecomStatsLog 74 .TELECOM_ERROR_STATS__ERROR__ERROR_AUDIO_ROUTE_RETRY_REJECTED; 75 public static final int ERROR_BT_GET_SERVICE_FAILURE = TelecomStatsLog 76 .TELECOM_ERROR_STATS__ERROR__ERROR_BT_GET_SERVICE_FAILURE; 77 public static final int ERROR_BT_REGISTER_CALLBACK_FAILURE = TelecomStatsLog 78 .TELECOM_ERROR_STATS__ERROR__ERROR_BT_REGISTER_CALLBACK_FAILURE; 79 public static final int ERROR_AUDIO_ROUTE_UNAVAILABLE = TelecomStatsLog 80 .TELECOM_ERROR_STATS__ERROR__ERROR_AUDIO_ROUTE_UNAVAILABLE; 81 public static final int ERROR_EMERGENCY_NUMBER_DETERMINED_FAILURE = TelecomStatsLog 82 .TELECOM_ERROR_STATS__ERROR__ERROR_EMERGENCY_NUMBER_DETERMINED_FAILURE; 83 public static final int ERROR_NOTIFY_CALL_STREAM_START_FAILURE = TelecomStatsLog 84 .TELECOM_ERROR_STATS__ERROR__ERROR_NOTIFY_CALL_STREAM_START_FAILURE; 85 public static final int ERROR_NOTIFY_CALL_STREAM_STATE_CHANGED_FAILURE = TelecomStatsLog 86 .TELECOM_ERROR_STATS__ERROR__ERROR_NOTIFY_CALL_STREAM_STATE_CHANGED_FAILURE; 87 public static final int ERROR_NOTIFY_CALL_STREAM_STOP_FAILURE = TelecomStatsLog 88 .TELECOM_ERROR_STATS__ERROR__ERROR_NOTIFY_CALL_STREAM_STOP_FAILURE; 89 public static final int ERROR_RTT_STREAM_CLOSE_FAILURE = TelecomStatsLog 90 .TELECOM_ERROR_STATS__ERROR__ERROR_RTT_STREAM_CLOSE_FAILURE; 91 public static final int ERROR_RTT_STREAM_CREATE_FAILURE = TelecomStatsLog 92 .TELECOM_ERROR_STATS__ERROR__ERROR_RTT_STREAM_CREATE_FAILURE; 93 public static final int ERROR_SET_MUTED_FAILURE = TelecomStatsLog 94 .TELECOM_ERROR_STATS__ERROR__ERROR_SET_MUTED_FAILURE; 95 public static final int ERROR_VIDEO_PROVIDER_SET_FAILURE = TelecomStatsLog 96 .TELECOM_ERROR_STATS__ERROR__ERROR_VIDEO_PROVIDER_SET_FAILURE; 97 public static final int ERROR_WIRED_HEADSET_NOT_AVAILABLE = TelecomStatsLog 98 .TELECOM_ERROR_STATS__ERROR__ERROR_WIRED_HEADSET_NOT_AVAILABLE; 99 public static final int ERROR_LOG_CALL_FAILURE = TelecomStatsLog 100 .TELECOM_ERROR_STATS__ERROR__ERROR_LOG_CALL_FAILURE; 101 public static final int ERROR_RETRIEVING_ACCOUNT_EMERGENCY = TelecomStatsLog 102 .TELECOM_ERROR_STATS__ERROR__ERROR_RETRIEVING_ACCOUNT_EMERGENCY; 103 public static final int ERROR_RETRIEVING_ACCOUNT = TelecomStatsLog 104 .TELECOM_ERROR_STATS__ERROR__ERROR_RETRIEVING_ACCOUNT; 105 public static final int ERROR_EMERGENCY_CALL_ABORTED_NO_ACCOUNT = TelecomStatsLog 106 .TELECOM_ERROR_STATS__ERROR__ERROR_EMERGENCY_CALL_ABORTED_NO_ACCOUNT; 107 public static final int ERROR_DEFAULT_MO_ACCOUNT_MISMATCH = TelecomStatsLog 108 .TELECOM_ERROR_STATS__ERROR__ERROR_DEFAULT_MO_ACCOUNT_MISMATCH; 109 public static final int ERROR_ESTABLISHING_CONNECTION = TelecomStatsLog 110 .TELECOM_ERROR_STATS__ERROR__ERROR_ESTABLISHING_CONNECTION; 111 public static final int ERROR_REMOVING_CALL = TelecomStatsLog 112 .TELECOM_ERROR_STATS__ERROR__ERROR_REMOVING_CALL; 113 public static final int ERROR_STUCK_CONNECTING_EMERGENCY = TelecomStatsLog 114 .TELECOM_ERROR_STATS__ERROR__ERROR_STUCK_CONNECTING_EMERGENCY; 115 public static final int ERROR_STUCK_CONNECTING = TelecomStatsLog 116 .TELECOM_ERROR_STATS__ERROR__ERROR_STUCK_CONNECTING; 117 private static final String TAG = ErrorStats.class.getSimpleName(); 118 private static final String FILE_NAME = "error_stats"; 119 private Map<ErrorEvent, Integer> mErrorStatsMap; 120 ErrorStats(@onNull Context context, @NonNull Looper looper, boolean isTestMode)121 public ErrorStats(@NonNull Context context, @NonNull Looper looper, boolean isTestMode) { 122 super(context, looper, isTestMode); 123 } 124 125 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 126 @Override getTag()127 public int getTag() { 128 return TELECOM_ERROR_STATS; 129 } 130 131 @Override getFileName()132 protected String getFileName() { 133 return FILE_NAME; 134 } 135 136 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 137 @Override onPull(final List<StatsEvent> data)138 public synchronized int onPull(final List<StatsEvent> data) { 139 if (mPulledAtoms.telecomErrorStats.length != 0) { 140 Arrays.stream(mPulledAtoms.telecomErrorStats).forEach(v -> data.add( 141 TelecomStatsLog.buildStatsEvent(getTag(), 142 v.getSubmodule(), v.getError(), v.getCount()))); 143 mErrorStatsMap.clear(); 144 onAggregate(); 145 return StatsManager.PULL_SUCCESS; 146 } else { 147 return StatsManager.PULL_SKIP; 148 } 149 } 150 151 @Override onLoad()152 protected synchronized void onLoad() { 153 if (mPulledAtoms.telecomErrorStats != null) { 154 mErrorStatsMap = new HashMap<>(); 155 for (PulledAtomsClass.TelecomErrorStats v : mPulledAtoms.telecomErrorStats) { 156 mErrorStatsMap.put(new ErrorEvent(v.getSubmodule(), v.getError()), 157 v.getCount()); 158 } 159 mLastPulledTimestamps = mPulledAtoms.getTelecomErrorStatsPullTimestampMillis(); 160 } 161 } 162 163 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 164 @Override onAggregate()165 public synchronized void onAggregate() { 166 Log.d(TAG, "onAggregate: %s", mErrorStatsMap); 167 clearAtoms(); 168 if (mErrorStatsMap.isEmpty()) { 169 return; 170 } 171 mPulledAtoms.setTelecomErrorStatsPullTimestampMillis(mLastPulledTimestamps); 172 mPulledAtoms.telecomErrorStats = 173 new PulledAtomsClass.TelecomErrorStats[mErrorStatsMap.size()]; 174 int[] index = new int[1]; 175 mErrorStatsMap.forEach((k, v) -> { 176 mPulledAtoms.telecomErrorStats[index[0]] = new PulledAtomsClass.TelecomErrorStats(); 177 mPulledAtoms.telecomErrorStats[index[0]].setSubmodule(k.mModuleId); 178 mPulledAtoms.telecomErrorStats[index[0]].setError(k.mErrorId); 179 mPulledAtoms.telecomErrorStats[index[0]].setCount(v); 180 index[0]++; 181 }); 182 save(DELAY_FOR_PERSISTENT_MILLIS); 183 } 184 log(@ubModuleId int moduleId, @ErrorId int errorId)185 public void log(@SubModuleId int moduleId, @ErrorId int errorId) { 186 post(() -> { 187 ErrorEvent key = new ErrorEvent(moduleId, errorId); 188 mErrorStatsMap.put(key, mErrorStatsMap.getOrDefault(key, 0) + 1); 189 onAggregate(); 190 }); 191 } 192 193 @IntDef(prefix = "SUB", value = { 194 SUB_UNKNOWN, 195 SUB_CALL_AUDIO, 196 SUB_CALL_LOGS, 197 SUB_CALL_MANAGER, 198 SUB_CONNECTION_SERVICE, 199 SUB_EMERGENCY_CALL, 200 SUB_IN_CALL_SERVICE, 201 SUB_MISC, 202 SUB_PHONE_ACCOUNT, 203 SUB_SYSTEM_SERVICE, 204 SUB_TELEPHONY, 205 SUB_UI, 206 SUB_VOIP_CALL, 207 }) 208 @Retention(RetentionPolicy.SOURCE) 209 public @interface SubModuleId { 210 } 211 212 @IntDef(prefix = "ERROR", value = { 213 ERROR_UNKNOWN, 214 ERROR_EXTERNAL_EXCEPTION, 215 ERROR_INTERNAL_EXCEPTION, 216 ERROR_AUDIO_ROUTE_RETRY_REJECTED, 217 ERROR_BT_GET_SERVICE_FAILURE, 218 ERROR_BT_REGISTER_CALLBACK_FAILURE, 219 ERROR_AUDIO_ROUTE_UNAVAILABLE, 220 ERROR_EMERGENCY_NUMBER_DETERMINED_FAILURE, 221 ERROR_NOTIFY_CALL_STREAM_START_FAILURE, 222 ERROR_NOTIFY_CALL_STREAM_STATE_CHANGED_FAILURE, 223 ERROR_NOTIFY_CALL_STREAM_STOP_FAILURE, 224 ERROR_RTT_STREAM_CLOSE_FAILURE, 225 ERROR_RTT_STREAM_CREATE_FAILURE, 226 ERROR_SET_MUTED_FAILURE, 227 ERROR_VIDEO_PROVIDER_SET_FAILURE, 228 ERROR_WIRED_HEADSET_NOT_AVAILABLE, 229 ERROR_LOG_CALL_FAILURE, 230 ERROR_RETRIEVING_ACCOUNT_EMERGENCY, 231 ERROR_RETRIEVING_ACCOUNT, 232 ERROR_EMERGENCY_CALL_ABORTED_NO_ACCOUNT, 233 ERROR_DEFAULT_MO_ACCOUNT_MISMATCH, 234 ERROR_ESTABLISHING_CONNECTION, 235 ERROR_REMOVING_CALL, 236 ERROR_STUCK_CONNECTING_EMERGENCY, 237 ERROR_STUCK_CONNECTING, 238 }) 239 @Retention(RetentionPolicy.SOURCE) 240 public @interface ErrorId { 241 } 242 243 static class ErrorEvent { 244 245 final @SubModuleId int mModuleId; 246 final @ErrorId int mErrorId; 247 ErrorEvent(@ubModuleId int moduleId, @ErrorId int errorId)248 ErrorEvent(@SubModuleId int moduleId, @ErrorId int errorId) { 249 mModuleId = moduleId; 250 mErrorId = errorId; 251 } 252 253 @Override equals(Object other)254 public boolean equals(Object other) { 255 if (this == other) { 256 return true; 257 } 258 if (!(other instanceof ErrorEvent obj)) { 259 return false; 260 } 261 return this.mModuleId == obj.mModuleId && this.mErrorId == obj.mErrorId; 262 } 263 264 @Override hashCode()265 public int hashCode() { 266 return Objects.hash(mModuleId, mErrorId); 267 } 268 269 @Override toString()270 public String toString() { 271 return "[ErrorEvent: mModuleId=" + mModuleId + ", mErrorId=" + mErrorId + "]"; 272 } 273 } 274 } 275