1 /* 2 * Copyright (C) 2023 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.credentials.metrics; 18 19 import com.android.server.credentials.MetricUtilities; 20 import com.android.server.credentials.ProviderSession; 21 import com.android.server.credentials.metrics.shared.ResponseCollective; 22 23 import java.util.LinkedHashMap; 24 import java.util.Map; 25 26 /** 27 * This will generate most of its data via using the information of {@link CandidatePhaseMetric} 28 * across all the providers. This belongs to the metric flow where the calling app is known. It 29 * also contains {@link BrowsedAuthenticationMetric} data aggregated within. 30 */ 31 public class CandidateAggregateMetric { 32 33 private static final String TAG = "CandidateTotalMetric"; 34 // The session id of this provider metric 35 private final int mSessionIdProvider; 36 // Indicates if this provider returned from the candidate query phase, 37 // true if at least one provider returns validly, even if empty, default false 38 private boolean mQueryReturned = false; 39 // For reference, the initial log timestamp when the service started running the API call, 40 // defaults to -1 41 private long mServiceBeganTimeNanoseconds = -1; 42 // Indicates the total number of providers this aggregate captures information for, default 0 43 private int mNumProviders = 0; 44 // Indicates if the authentication entry returned, true if at least one entry returns validly, 45 // even if empty, default false 46 private boolean mAuthReturned = false; 47 // Indicates the total number of authentication entries that were tapped in aggregate, default 0 48 private int mNumAuthEntriesTapped = 0; 49 // The combined aggregate collective across the candidate get/create 50 private ResponseCollective mAggregateCollectiveQuery = 51 new ResponseCollective(Map.of(), Map.of()); 52 // The combined aggregate collective across the auth entry info 53 private ResponseCollective mAggregateCollectiveAuth = 54 new ResponseCollective(Map.of(), Map.of()); 55 // The minimum of all the providers query start time, defaults to -1 56 private long mMinProviderTimestampNanoseconds = -1; 57 // The maximum of all the providers query finish time, defaults to -1 58 private long mMaxProviderTimestampNanoseconds = -1; 59 // The total number of failures across all the providers, defaults to 0 60 private int mTotalQueryFailures = 0; 61 // The map of all seen framework exceptions and their counts across all providers, default empty 62 private Map<String, Integer> mExceptionCountQuery = new LinkedHashMap<>(); 63 // The total number of failures across all auth entries, defaults to 0 64 private int mTotalAuthFailures = 0; 65 // The map of all seen framework exceptions and their counts across auth entries, default empty 66 private Map<String, Integer> mExceptionCountAuth = new LinkedHashMap<>(); 67 CandidateAggregateMetric(int sessionIdTrackOne)68 public CandidateAggregateMetric(int sessionIdTrackOne) { 69 mSessionIdProvider = sessionIdTrackOne; 70 } 71 getSessionIdProvider()72 public int getSessionIdProvider() { 73 return mSessionIdProvider; 74 } 75 76 /** 77 * This will take all the candidate data captured and aggregate that information. 78 * @param providers the providers associated with the candidate flow 79 */ collectAverages(Map<String, ProviderSession> providers)80 public void collectAverages(Map<String, ProviderSession> providers) { 81 collectQueryAggregates(providers); 82 collectAuthAggregates(providers); 83 } 84 collectQueryAggregates(Map<String, ProviderSession> providers)85 private void collectQueryAggregates(Map<String, ProviderSession> providers) { 86 mNumProviders = providers.size(); 87 Map<String, Integer> responseCountQuery = new LinkedHashMap<>(); 88 Map<EntryEnum, Integer> entryCountQuery = new LinkedHashMap<>(); 89 var providerSessions = providers.values(); 90 long min_query_start = Long.MAX_VALUE; 91 long max_query_end = Long.MIN_VALUE; 92 for (var session : providerSessions) { 93 var sessionMetric = session.getProviderSessionMetric(); 94 var candidateMetric = sessionMetric.getCandidatePhasePerProviderMetric(); 95 if (candidateMetric.getCandidateUid() == MetricUtilities.DEFAULT_INT_32) { 96 mNumProviders--; 97 continue; // Do not aggregate this one and reduce the size of actual candidates 98 } 99 if (mServiceBeganTimeNanoseconds == -1) { 100 mServiceBeganTimeNanoseconds = candidateMetric.getServiceBeganTimeNanoseconds(); 101 } 102 mQueryReturned = mQueryReturned || candidateMetric.isQueryReturned(); 103 ResponseCollective candidateCollective = candidateMetric.getResponseCollective(); 104 ResponseCollective.combineTypeCountMaps(responseCountQuery, 105 candidateCollective.getResponseCountsMap()); 106 ResponseCollective.combineTypeCountMaps(entryCountQuery, 107 candidateCollective.getEntryCountsMap()); 108 min_query_start = Math.min(min_query_start, 109 candidateMetric.getStartQueryTimeNanoseconds()); 110 max_query_end = Math.max(max_query_end, candidateMetric 111 .getQueryFinishTimeNanoseconds()); 112 mTotalQueryFailures += (candidateMetric.isHasException() ? 1 : 0); 113 if (!candidateMetric.getFrameworkException().isEmpty()) { 114 mExceptionCountQuery.put(candidateMetric.getFrameworkException(), 115 mExceptionCountQuery.getOrDefault( 116 candidateMetric.getFrameworkException(), 0) + 1); 117 } 118 } 119 mMinProviderTimestampNanoseconds = min_query_start; 120 mMaxProviderTimestampNanoseconds = max_query_end; 121 mAggregateCollectiveQuery = new ResponseCollective(responseCountQuery, entryCountQuery); 122 } 123 collectAuthAggregates(Map<String, ProviderSession> providers)124 private void collectAuthAggregates(Map<String, ProviderSession> providers) { 125 Map<String, Integer> responseCountAuth = new LinkedHashMap<>(); 126 Map<EntryEnum, Integer> entryCountAuth = new LinkedHashMap<>(); 127 var providerSessions = providers.values(); 128 for (var session : providerSessions) { 129 var sessionMetric = session.getProviderSessionMetric(); 130 var authMetrics = sessionMetric.getBrowsedAuthenticationMetric(); 131 for (var authMetric : authMetrics) { 132 if (authMetric.getProviderUid() == MetricUtilities.DEFAULT_INT_32) { 133 continue; // skip this unfilled base auth entry 134 } 135 mNumAuthEntriesTapped++; 136 mAuthReturned = mAuthReturned || authMetric.isAuthReturned(); 137 ResponseCollective authCollective = authMetric.getAuthEntryCollective(); 138 ResponseCollective.combineTypeCountMaps(responseCountAuth, 139 authCollective.getResponseCountsMap()); 140 ResponseCollective.combineTypeCountMaps(entryCountAuth, 141 authCollective.getEntryCountsMap()); 142 mTotalQueryFailures += (authMetric.isHasException() ? 1 : 0); 143 if (!authMetric.getFrameworkException().isEmpty()) { 144 mExceptionCountQuery.put(authMetric.getFrameworkException(), 145 mExceptionCountQuery.getOrDefault( 146 authMetric.getFrameworkException(), 0) + 1); 147 } 148 } 149 } 150 mAggregateCollectiveAuth = new ResponseCollective(responseCountAuth, entryCountAuth); 151 } 152 getNumProviders()153 public int getNumProviders() { 154 return mNumProviders; 155 } 156 isQueryReturned()157 public boolean isQueryReturned() { 158 return mQueryReturned; 159 } 160 161 getNumAuthEntriesTapped()162 public int getNumAuthEntriesTapped() { 163 return mNumAuthEntriesTapped; 164 } 165 getAggregateCollectiveQuery()166 public ResponseCollective getAggregateCollectiveQuery() { 167 return mAggregateCollectiveQuery; 168 } 169 getAggregateCollectiveAuth()170 public ResponseCollective getAggregateCollectiveAuth() { 171 return mAggregateCollectiveAuth; 172 } 173 isAuthReturned()174 public boolean isAuthReturned() { 175 return mAuthReturned; 176 } 177 getMaxProviderTimestampNanoseconds()178 public long getMaxProviderTimestampNanoseconds() { 179 return mMaxProviderTimestampNanoseconds; 180 } 181 getMinProviderTimestampNanoseconds()182 public long getMinProviderTimestampNanoseconds() { 183 return mMinProviderTimestampNanoseconds; 184 } 185 getTotalQueryFailures()186 public int getTotalQueryFailures() { 187 return mTotalQueryFailures; 188 } 189 190 /** 191 * Returns the unique, deduped, exception classtypes for logging associated with this provider. 192 * 193 * @return a string array for deduped exception classtypes 194 */ getUniqueExceptionStringsQuery()195 public String[] getUniqueExceptionStringsQuery() { 196 String[] result = new String[mExceptionCountQuery.keySet().size()]; 197 mExceptionCountQuery.keySet().toArray(result); 198 return result; 199 } 200 201 /** 202 * Returns the unique, deduped, exception classtype counts for logging associated with this 203 * provider. 204 * 205 * @return a string array for deduped classtype exception counts 206 */ getUniqueExceptionCountsQuery()207 public int[] getUniqueExceptionCountsQuery() { 208 return mExceptionCountQuery.values().stream().mapToInt(Integer::intValue).toArray(); 209 } 210 211 /** 212 * Returns the unique, deduped, exception classtypes for logging associated with this provider 213 * for auth entries. 214 * 215 * @return a string array for deduped exception classtypes for auth entries 216 */ getUniqueExceptionStringsAuth()217 public String[] getUniqueExceptionStringsAuth() { 218 String[] result = new String[mExceptionCountAuth.keySet().size()]; 219 mExceptionCountAuth.keySet().toArray(result); 220 return result; 221 } 222 223 /** 224 * Returns the unique, deduped, exception classtype counts for logging associated with this 225 * provider for auth entries. 226 * 227 * @return a string array for deduped classtype exception counts for auth entries 228 */ getUniqueExceptionCountsAuth()229 public int[] getUniqueExceptionCountsAuth() { 230 return mExceptionCountAuth.values().stream().mapToInt(Integer::intValue).toArray(); 231 } 232 getServiceBeganTimeNanoseconds()233 public long getServiceBeganTimeNanoseconds() { 234 return mServiceBeganTimeNanoseconds; 235 } 236 getTotalAuthFailures()237 public int getTotalAuthFailures() { 238 return mTotalAuthFailures; 239 } 240 } 241