blob: 91547788a23beac1b843c4d3c267afa23f0f3419 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.credentials.metrics;
import com.android.server.credentials.MetricUtilities;
import com.android.server.credentials.ProviderSession;
import com.android.server.credentials.metrics.shared.ResponseCollective;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* This will generate most of its data via using the information of {@link CandidatePhaseMetric}
* across all the providers. This belongs to the metric flow where the calling app is known. It
* also contains {@link BrowsedAuthenticationMetric} data aggregated within.
*/
public class CandidateAggregateMetric {
private static final String TAG = "CandidateTotalMetric";
// The session id of this provider metric
private final int mSessionIdProvider;
// Indicates if this provider returned from the candidate query phase,
// true if at least one provider returns validly, even if empty, default false
private boolean mQueryReturned = false;
// For reference, the initial log timestamp when the service started running the API call,
// defaults to -1
private long mServiceBeganTimeNanoseconds = -1;
// Indicates the total number of providers this aggregate captures information for, default 0
private int mNumProviders = 0;
// Indicates if the authentication entry returned, true if at least one entry returns validly,
// even if empty, default false
private boolean mAuthReturned = false;
// Indicates the total number of authentication entries that were tapped in aggregate, default 0
private int mNumAuthEntriesTapped = 0;
// The combined aggregate collective across the candidate get/create
private ResponseCollective mAggregateCollectiveQuery =
new ResponseCollective(Map.of(), Map.of());
// The combined aggregate collective across the auth entry info
private ResponseCollective mAggregateCollectiveAuth =
new ResponseCollective(Map.of(), Map.of());
// The minimum of all the providers query start time, defaults to -1
private long mMinProviderTimestampNanoseconds = -1;
// The maximum of all the providers query finish time, defaults to -1
private long mMaxProviderTimestampNanoseconds = -1;
// The total number of failures across all the providers, defaults to 0
private int mTotalQueryFailures = 0;
// The map of all seen framework exceptions and their counts across all providers, default empty
private Map<String, Integer> mExceptionCountQuery = new LinkedHashMap<>();
// The total number of failures across all auth entries, defaults to 0
private int mTotalAuthFailures = 0;
// The map of all seen framework exceptions and their counts across auth entries, default empty
private Map<String, Integer> mExceptionCountAuth = new LinkedHashMap<>();
public CandidateAggregateMetric(int sessionIdTrackOne) {
mSessionIdProvider = sessionIdTrackOne;
}
public int getSessionIdProvider() {
return mSessionIdProvider;
}
/**
* This will take all the candidate data captured and aggregate that information.
* @param providers the providers associated with the candidate flow
*/
public void collectAverages(Map<String, ProviderSession> providers) {
collectQueryAggregates(providers);
collectAuthAggregates(providers);
}
private void collectQueryAggregates(Map<String, ProviderSession> providers) {
mNumProviders = providers.size();
Map<String, Integer> responseCountQuery = new LinkedHashMap<>();
Map<EntryEnum, Integer> entryCountQuery = new LinkedHashMap<>();
var providerSessions = providers.values();
long min_query_start = Long.MAX_VALUE;
long max_query_end = Long.MIN_VALUE;
for (var session : providerSessions) {
var sessionMetric = session.getProviderSessionMetric();
var candidateMetric = sessionMetric.getCandidatePhasePerProviderMetric();
if (candidateMetric.getCandidateUid() == MetricUtilities.DEFAULT_INT_32) {
mNumProviders--;
continue; // Do not aggregate this one and reduce the size of actual candidates
}
if (mServiceBeganTimeNanoseconds == -1) {
mServiceBeganTimeNanoseconds = candidateMetric.getServiceBeganTimeNanoseconds();
}
mQueryReturned = mQueryReturned || candidateMetric.isQueryReturned();
ResponseCollective candidateCollective = candidateMetric.getResponseCollective();
ResponseCollective.combineTypeCountMaps(responseCountQuery,
candidateCollective.getResponseCountsMap());
ResponseCollective.combineTypeCountMaps(entryCountQuery,
candidateCollective.getEntryCountsMap());
min_query_start = Math.min(min_query_start,
candidateMetric.getStartQueryTimeNanoseconds());
max_query_end = Math.max(max_query_end, candidateMetric
.getQueryFinishTimeNanoseconds());
mTotalQueryFailures += (candidateMetric.isHasException() ? 1 : 0);
if (!candidateMetric.getFrameworkException().isEmpty()) {
mExceptionCountQuery.put(candidateMetric.getFrameworkException(),
mExceptionCountQuery.getOrDefault(
candidateMetric.getFrameworkException(), 0) + 1);
}
}
mMinProviderTimestampNanoseconds = min_query_start;
mMaxProviderTimestampNanoseconds = max_query_end;
mAggregateCollectiveQuery = new ResponseCollective(responseCountQuery, entryCountQuery);
}
private void collectAuthAggregates(Map<String, ProviderSession> providers) {
Map<String, Integer> responseCountAuth = new LinkedHashMap<>();
Map<EntryEnum, Integer> entryCountAuth = new LinkedHashMap<>();
var providerSessions = providers.values();
for (var session : providerSessions) {
var sessionMetric = session.getProviderSessionMetric();
var authMetrics = sessionMetric.getBrowsedAuthenticationMetric();
for (var authMetric : authMetrics) {
if (authMetric.getProviderUid() == MetricUtilities.DEFAULT_INT_32) {
continue; // skip this unfilled base auth entry
}
mNumAuthEntriesTapped++;
mAuthReturned = mAuthReturned || authMetric.isAuthReturned();
ResponseCollective authCollective = authMetric.getAuthEntryCollective();
ResponseCollective.combineTypeCountMaps(responseCountAuth,
authCollective.getResponseCountsMap());
ResponseCollective.combineTypeCountMaps(entryCountAuth,
authCollective.getEntryCountsMap());
mTotalQueryFailures += (authMetric.isHasException() ? 1 : 0);
if (!authMetric.getFrameworkException().isEmpty()) {
mExceptionCountQuery.put(authMetric.getFrameworkException(),
mExceptionCountQuery.getOrDefault(
authMetric.getFrameworkException(), 0) + 1);
}
}
}
mAggregateCollectiveAuth = new ResponseCollective(responseCountAuth, entryCountAuth);
}
public int getNumProviders() {
return mNumProviders;
}
public boolean isQueryReturned() {
return mQueryReturned;
}
public int getNumAuthEntriesTapped() {
return mNumAuthEntriesTapped;
}
public ResponseCollective getAggregateCollectiveQuery() {
return mAggregateCollectiveQuery;
}
public ResponseCollective getAggregateCollectiveAuth() {
return mAggregateCollectiveAuth;
}
public boolean isAuthReturned() {
return mAuthReturned;
}
public long getMaxProviderTimestampNanoseconds() {
return mMaxProviderTimestampNanoseconds;
}
public long getMinProviderTimestampNanoseconds() {
return mMinProviderTimestampNanoseconds;
}
public int getTotalQueryFailures() {
return mTotalQueryFailures;
}
/**
* Returns the unique, deduped, exception classtypes for logging associated with this provider.
*
* @return a string array for deduped exception classtypes
*/
public String[] getUniqueExceptionStringsQuery() {
String[] result = new String[mExceptionCountQuery.keySet().size()];
mExceptionCountQuery.keySet().toArray(result);
return result;
}
/**
* Returns the unique, deduped, exception classtype counts for logging associated with this
* provider.
*
* @return a string array for deduped classtype exception counts
*/
public int[] getUniqueExceptionCountsQuery() {
return mExceptionCountQuery.values().stream().mapToInt(Integer::intValue).toArray();
}
/**
* Returns the unique, deduped, exception classtypes for logging associated with this provider
* for auth entries.
*
* @return a string array for deduped exception classtypes for auth entries
*/
public String[] getUniqueExceptionStringsAuth() {
String[] result = new String[mExceptionCountAuth.keySet().size()];
mExceptionCountAuth.keySet().toArray(result);
return result;
}
/**
* Returns the unique, deduped, exception classtype counts for logging associated with this
* provider for auth entries.
*
* @return a string array for deduped classtype exception counts for auth entries
*/
public int[] getUniqueExceptionCountsAuth() {
return mExceptionCountAuth.values().stream().mapToInt(Integer::intValue).toArray();
}
public long getServiceBeganTimeNanoseconds() {
return mServiceBeganTimeNanoseconds;
}
public int getTotalAuthFailures() {
return mTotalAuthFailures;
}
}