diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 06b96eb46ac1d..f7932bfdc3f16 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -58,7 +58,6 @@ import android.provider.Settings; import android.service.credentials.CallingAppInfo; import android.service.credentials.CredentialProviderInfoFactory; import android.text.TextUtils; -import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -472,7 +471,7 @@ public final class CredentialManagerService GetCredentialException.TYPE_NO_CREDENTIAL, "No credentials available on this device."); } catch (RemoteException e) { - Log.i( + Slog.i( TAG, "Issue invoking onError on IGetCredentialCallback " + "callback: " @@ -528,7 +527,7 @@ public final class CredentialManagerService false, null, false, false, null)); } catch (RemoteException e) { - Log.i( + Slog.i( TAG, "Issue invoking onError on IGetCredentialCallback " + "callback: " @@ -673,7 +672,7 @@ public final class CredentialManagerService MetricUtilities.logApiCalledInitialPhase(initMetric, session.mRequestSessionMetric.returnIncrementSequence()); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: ", e); + Slog.w(TAG, "Unexpected error during metric logging: ", e); } } @@ -706,7 +705,7 @@ public final class CredentialManagerService Settings.Secure.CREDENTIAL_SERVICE, storedValue, userId)) { - Log.e(TAG, "Failed to store setting containing enabled providers"); + Slog.e(TAG, "Failed to store setting containing enabled providers"); try { callback.onError( "failed_setting_store", @@ -962,7 +961,7 @@ public final class CredentialManagerService @Override @GuardedBy("mLock") public void onFinishRequestSession(@UserIdInt int userId, IBinder token) { - Log.i(TAG, "In onFinishRequestSession"); + Slog.i(TAG, "In onFinishRequestSession"); if (mRequestSessions.get(userId) != null) { mRequestSessions.get(userId).remove(token); } diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index 4e82ee71ac1b4..31c2a52f3c367 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -19,7 +19,7 @@ package com.android.server.credentials; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; -import android.util.Log; +import android.util.Slog; import com.android.internal.util.FrameworkStatsLog; import com.android.server.credentials.metrics.ApiName; @@ -27,6 +27,7 @@ import com.android.server.credentials.metrics.ApiStatus; import com.android.server.credentials.metrics.CandidateBrowsingPhaseMetric; import com.android.server.credentials.metrics.CandidatePhaseMetric; import com.android.server.credentials.metrics.ChosenProviderFinalPhaseMetric; +import com.android.server.credentials.metrics.EntryEnum; import com.android.server.credentials.metrics.InitialPhaseMetric; import java.util.List; @@ -69,7 +70,7 @@ public class MetricUtilities { componentName.getPackageName(), PackageManager.ApplicationInfoFlags.of(0)).uid; } catch (Throwable t) { - Log.i(TAG, "Couldn't find required uid"); + Slog.i(TAG, "Couldn't find required uid"); } return sessUid; } @@ -147,28 +148,28 @@ public class MetricUtilities { .getFinalFinishTimeNanoseconds()), /* chosen_provider_status */ finalPhaseMetric.getChosenProviderStatus(), /* chosen_provider_has_exception */ finalPhaseMetric.isHasException(), - /* chosen_provider_available_entries */ finalPhaseMetric.getAvailableEntries() - .stream().mapToInt(i -> i).toArray(), - /* chosen_provider_action_entry_count */ finalPhaseMetric.getActionEntryCount(), - /* chosen_provider_credential_entry_count */ - finalPhaseMetric.getCredentialEntryCount(), - /* chosen_provider_credential_entry_type_count */ - finalPhaseMetric.getCredentialEntryTypeCount(), - /* chosen_provider_remote_entry_count */ - finalPhaseMetric.getRemoteEntryCount(), - /* chosen_provider_authentication_entry_count */ - finalPhaseMetric.getAuthenticationEntryCount(), + /* chosen_provider_available_entries (deprecated) */ DEFAULT_REPEATED_INT_32, + /* chosen_provider_action_entry_count (deprecated) */ DEFAULT_INT_32, + /* chosen_provider_credential_entry_count (deprecated)*/DEFAULT_INT_32, + /* chosen_provider_credential_entry_type_count (deprecated) */ DEFAULT_INT_32, + /* chosen_provider_remote_entry_count (deprecated) */ DEFAULT_INT_32, + /* chosen_provider_authentication_entry_count (deprecated) */ DEFAULT_INT_32, /* clicked_entries */ browsedClickedEntries, /* provider_of_clicked_entry */ browsedProviderUid, /* api_status */ apiStatus, - DEFAULT_REPEATED_INT_32, - DEFAULT_REPEATED_INT_32, - DEFAULT_REPEATED_STR, - DEFAULT_REPEATED_INT_32, + /* unique_entries */ + finalPhaseMetric.getResponseCollective().getUniqueEntries(), + /* per_entry_counts */ + finalPhaseMetric.getResponseCollective().getUniqueEntryCounts(), + /* unique_response_classtypes */ + finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(), + /* per_classtype_counts */ + finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(), + /* framework_exception_unique_classtypes */ DEFAULT_STRING ); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } @@ -223,12 +224,18 @@ public class MetricUtilities { metric.getQueryFinishTimeNanoseconds()); candidateStatusList[index] = metric.getProviderQueryStatus(); candidateHasExceptionList[index] = metric.isHasException(); - candidateTotalEntryCountList[index] = metric.getNumEntriesTotal(); - candidateCredentialEntryCountList[index] = metric.getCredentialEntryCount(); - candidateCredentialTypeCountList[index] = metric.getCredentialEntryTypeCount(); - candidateActionEntryCountList[index] = metric.getActionEntryCount(); - candidateAuthEntryCountList[index] = metric.getAuthenticationEntryCount(); - candidateRemoteEntryCountList[index] = metric.getRemoteEntryCount(); + candidateTotalEntryCountList[index] = metric.getResponseCollective() + .getNumEntriesTotal(); + candidateCredentialEntryCountList[index] = metric.getResponseCollective() + .getCountForEntry(EntryEnum.CREDENTIAL_ENTRY); + candidateCredentialTypeCountList[index] = metric.getResponseCollective() + .getUniqueResponseStrings().length; + candidateActionEntryCountList[index] = metric.getResponseCollective() + .getCountForEntry(EntryEnum.ACTION_ENTRY); + candidateAuthEntryCountList[index] = metric.getResponseCollective() + .getCountForEntry(EntryEnum.AUTHENTICATION_ENTRY); + candidateRemoteEntryCountList[index] = metric.getResponseCollective() + .getCountForEntry(EntryEnum.REMOTE_ENTRY); frameworkExceptionList[index] = metric.getFrameworkException(); index++; } @@ -262,7 +269,7 @@ public class MetricUtilities { initialPhaseMetric.getUniqueRequestCounts() ); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } @@ -298,7 +305,7 @@ public class MetricUtilities { DEFAULT_INT_32, /* chosen_provider_status */ DEFAULT_INT_32); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } @@ -331,7 +338,7 @@ public class MetricUtilities { initialPhaseMetric.isOriginSpecified() ); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java index b212606b8271a..e3e91cc54b29c 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java @@ -16,14 +16,12 @@ package com.android.server.credentials.metrics; -import android.util.IntArray; import android.util.Log; import com.android.server.credentials.MetricUtilities; +import com.android.server.credentials.metrics.shared.ResponseCollective; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; +import java.util.Map; /** * The central candidate provider metric object that mimics our defined metric setup. @@ -55,23 +53,12 @@ public class CandidatePhaseMetric { private int mProviderQueryStatus = -1; // Indicates if an exception was thrown by this provider, false by default private boolean mHasException = false; - // Indicates the number of total entries available, defaults to -1 - private int mNumEntriesTotal = -1; - // The count of action entries from this provider, defaults to -1 - private int mActionEntryCount = -1; - // The count of credential entries from this provider, defaults to -1 - private int mCredentialEntryCount = -1; - // The *type-count* of the credential entries, defaults to -1 - private int mCredentialEntryTypeCount = -1; - // The count of remote entries from this provider, defaults to -1 - private int mRemoteEntryCount = -1; - // The count of authentication entries from this provider, defaults to -1 - private int mAuthenticationEntryCount = -1; - // Gathered to pass on to chosen provider when required - private final IntArray mAvailableEntries = new IntArray(); - // The *framework only* exception held by this provider, empty string by default private String mFrameworkException = ""; + // Stores the response credential information, as well as the response entry information which + // by default, contains empty info + private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of()); + public CandidatePhaseMetric() { } @@ -182,88 +169,13 @@ public class CandidatePhaseMetric { return mHasException; } - /* -------------- Number of Entries ---------------- */ - - public void setNumEntriesTotal(int numEntriesTotal) { - mNumEntriesTotal = numEntriesTotal; + /* -------------- The Entries and Responses Gathered ---------------- */ + public void setResponseCollective(ResponseCollective responseCollective) { + mResponseCollective = responseCollective; } - public int getNumEntriesTotal() { - return mNumEntriesTotal; - } - - /* -------------- Count of Action Entries ---------------- */ - - public void setActionEntryCount(int actionEntryCount) { - mActionEntryCount = actionEntryCount; - } - - public int getActionEntryCount() { - return mActionEntryCount; - } - - /* -------------- Count of Credential Entries ---------------- */ - - public void setCredentialEntryCount(int credentialEntryCount) { - mCredentialEntryCount = credentialEntryCount; - } - - public int getCredentialEntryCount() { - return mCredentialEntryCount; - } - - /* -------------- Count of Credential Entry Types ---------------- */ - - public void setCredentialEntryTypeCount(int credentialEntryTypeCount) { - mCredentialEntryTypeCount = credentialEntryTypeCount; - } - - public int getCredentialEntryTypeCount() { - return mCredentialEntryTypeCount; - } - - /* -------------- Count of Remote Entries ---------------- */ - - public void setRemoteEntryCount(int remoteEntryCount) { - mRemoteEntryCount = remoteEntryCount; - } - - public int getRemoteEntryCount() { - return mRemoteEntryCount; - } - - /* -------------- Count of Authentication Entries ---------------- */ - - public void setAuthenticationEntryCount(int authenticationEntryCount) { - mAuthenticationEntryCount = authenticationEntryCount; - } - - public int getAuthenticationEntryCount() { - return mAuthenticationEntryCount; - } - - /* -------------- The Entries Gathered ---------------- */ - - /** - * Allows adding an entry record to this metric collector, which can then be propagated to - * the final phase to retain information on the data available to the candidate. - * - * @param e the entry enum collected by the candidate provider associated with this metric - * collector - */ - public void addEntry(EntryEnum e) { - mAvailableEntries.add(e.getMetricCode()); - } - - /** - * Returns a safely copied list of the entries captured by this metric collector associated - * with a particular candidate provider. - * - * @return the full collection of entries encountered by the candidate provider associated with - * this metric - */ - public List getAvailableEntries() { - return Arrays.stream(mAvailableEntries.toArray()).boxed().collect(Collectors.toList()); + public ResponseCollective getResponseCollective() { + return mResponseCollective; } /* ------ Framework Exception for this Candidate ------ */ diff --git a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java index 8f08bb02dfd0c..64d33e6fdd766 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java @@ -19,9 +19,9 @@ package com.android.server.credentials.metrics; import android.util.Log; import com.android.server.credentials.MetricUtilities; +import com.android.server.credentials.metrics.shared.ResponseCollective; -import java.util.ArrayList; -import java.util.List; +import java.util.Map; /** * The central chosen provider metric object that mimics our defined metric setup. This is used @@ -66,21 +66,10 @@ public class ChosenProviderFinalPhaseMetric { private int mChosenProviderStatus = -1; // Indicates if an exception was thrown by this provider, false by default private boolean mHasException = false; - // Indicates the number of total entries available, defaults to -1. Not presently emitted, but - // left as a utility - private int mNumEntriesTotal = -1; - // The count of action entries from this provider, defaults to -1 - private int mActionEntryCount = -1; - // The count of credential entries from this provider, defaults to -1 - private int mCredentialEntryCount = -1; - // The *type-count* of the credential entries, defaults to -1 - private int mCredentialEntryTypeCount = -1; - // The count of remote entries from this provider, defaults to -1 - private int mRemoteEntryCount = -1; - // The count of authentication entries from this provider, defaults to -1 - private int mAuthenticationEntryCount = -1; - // Gathered to pass on to chosen provider when required - private List mAvailableEntries = new ArrayList<>(); + + // Stores the response credential information, as well as the response entry information which + // by default, contains empty info + private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of()); public ChosenProviderFinalPhaseMetric() { @@ -264,87 +253,6 @@ public class ChosenProviderFinalPhaseMetric { return mUiReturned; } - /* -------------- Number of Entries ---------------- */ - - public void setNumEntriesTotal(int numEntriesTotal) { - mNumEntriesTotal = numEntriesTotal; - } - - public int getNumEntriesTotal() { - return mNumEntriesTotal; - } - - /* -------------- Count of Action Entries ---------------- */ - - public void setActionEntryCount(int actionEntryCount) { - mActionEntryCount = actionEntryCount; - } - - public int getActionEntryCount() { - return mActionEntryCount; - } - - /* -------------- Count of Credential Entries ---------------- */ - - public void setCredentialEntryCount(int credentialEntryCount) { - mCredentialEntryCount = credentialEntryCount; - } - - public int getCredentialEntryCount() { - return mCredentialEntryCount; - } - - /* -------------- Count of Credential Entry Types ---------------- */ - - public void setCredentialEntryTypeCount(int credentialEntryTypeCount) { - mCredentialEntryTypeCount = credentialEntryTypeCount; - } - - public int getCredentialEntryTypeCount() { - return mCredentialEntryTypeCount; - } - - /* -------------- Count of Remote Entries ---------------- */ - - public void setRemoteEntryCount(int remoteEntryCount) { - mRemoteEntryCount = remoteEntryCount; - } - - public int getRemoteEntryCount() { - return mRemoteEntryCount; - } - - /* -------------- Count of Authentication Entries ---------------- */ - - public void setAuthenticationEntryCount(int authenticationEntryCount) { - mAuthenticationEntryCount = authenticationEntryCount; - } - - public int getAuthenticationEntryCount() { - return mAuthenticationEntryCount; - } - - /* -------------- The Entries Gathered ---------------- */ - - /** - * Sets the collected list of entries from the candidate phase to be retrievable in the - * chosen phase in a semantically correct way. - */ - public void setAvailableEntries(List entries) { - mAvailableEntries = new ArrayList<>(entries); // no alias copy - } - - /** - * Returns a list of the entries captured by this metric collector associated - * with a particular chosen provider. - * - * @return the full collection of entries encountered by the chosen provider during the - * candidate phase. - */ - public List getAvailableEntries() { - return new ArrayList<>(mAvailableEntries); // no alias copy - } - /* -------------- Has Exception ---------------- */ public void setHasException(boolean hasException) { @@ -354,4 +262,14 @@ public class ChosenProviderFinalPhaseMetric { public boolean isHasException() { return mHasException; } + + /* -------------- The Entries and Responses Gathered ---------------- */ + + public void setResponseCollective(ResponseCollective responseCollective) { + mResponseCollective = responseCollective; + } + + public ResponseCollective getResponseCollective() { + return mResponseCollective; + } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java index 5cfb0e7d375b0..3f10109b52d54 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java @@ -48,7 +48,7 @@ public class InitialPhaseMetric { // Indicates if the origin was specified when making this API request private boolean mOriginSpecified = false; - // Stores the deduped request information, particularly {"req":5}. + // Stores the deduped request information, particularly {"req":5} private Map mRequestCounts = new LinkedHashMap<>(); @@ -138,7 +138,7 @@ public class InitialPhaseMetric { } /** - * Reruns the unique, deduped, request classtypes for logging. + * Returns the unique, deduped, request classtypes for logging. * @return a string array for deduped classtypes */ public String[] getUniqueRequestStrings() { @@ -151,7 +151,7 @@ public class InitialPhaseMetric { } /** - * Reruns the unique, deduped, request classtype counts for logging. + * Returns the unique, deduped, request classtype counts for logging. * @return a string array for deduped classtype counts */ public int[] getUniqueRequestCounts() { diff --git a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java index 9a88255ce973c..7b671469dc8c7 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java @@ -16,15 +16,19 @@ package com.android.server.credentials.metrics; +import static com.android.server.credentials.MetricUtilities.DELTA_CUT; +import static com.android.server.credentials.MetricUtilities.generateMetricKey; + import android.annotation.NonNull; import android.service.credentials.BeginCreateCredentialResponse; import android.service.credentials.BeginGetCredentialResponse; -import android.service.credentials.CredentialEntry; -import android.util.Log; +import android.util.Slog; import com.android.server.credentials.MetricUtilities; +import com.android.server.credentials.metrics.shared.ResponseCollective; -import java.util.stream.Collectors; +import java.util.LinkedHashMap; +import java.util.Map; /** * Provides contextual metric collection for objects generated from @@ -68,7 +72,7 @@ public class ProviderSessionMetric { try { mCandidatePhasePerProviderMetric.setFrameworkException(exceptionType); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } @@ -97,7 +101,7 @@ public class ProviderSessionMetric { .getMetricCode()); } } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } @@ -118,7 +122,7 @@ public class ProviderSessionMetric { initMetric.getCredentialServiceStartedTimeNanoseconds()); mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } @@ -138,59 +142,53 @@ public class ProviderSessionMetric { beginCreateCredentialResponseCollectionCandidateEntryMetrics( (BeginCreateCredentialResponse) response); } else { - Log.i(TAG, "Your response type is unsupported for metric logging"); + Slog.i(TAG, "Your response type is unsupported for metric logging"); } } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Slog.w(TAG, "Unexpected error during metric logging: " + e); } } private void beginCreateCredentialResponseCollectionCandidateEntryMetrics( BeginCreateCredentialResponse response) { + Map entryCounts = new LinkedHashMap<>(); var createEntries = response.getCreateEntries(); - int numRemoteEntry = MetricUtilities.ZERO; - if (response.getRemoteCreateEntry() != null) { - numRemoteEntry = MetricUtilities.UNIT; - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY); - } - int numCreateEntries = - createEntries == null ? MetricUtilities.ZERO : createEntries.size(); - if (numCreateEntries > MetricUtilities.ZERO) { - createEntries.forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY)); - } - mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCreateEntries + numRemoteEntry); - mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry); - mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCreateEntries); - mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(MetricUtilities.UNIT); + int numRemoteEntry = response.getRemoteCreateEntry() != null ? MetricUtilities.ZERO : + MetricUtilities.UNIT; + int numCreateEntries = createEntries.size(); + entryCounts.put(EntryEnum.REMOTE_ENTRY, numRemoteEntry); + entryCounts.put(EntryEnum.CREDENTIAL_ENTRY, numCreateEntries); + + Map responseCounts = new LinkedHashMap<>(); + responseCounts.put(MetricUtilities.DEFAULT_STRING, numCreateEntries); + // We don't store create response because it's directly related to the request + // We do still store the count, however + + ResponseCollective responseCollective = new ResponseCollective(responseCounts, entryCounts); + mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective); } private void beginGetCredentialResponseCollectionCandidateEntryMetrics( BeginGetCredentialResponse response) { + Map entryCounts = new LinkedHashMap<>(); + Map responseCounts = new LinkedHashMap<>(); int numCredEntries = response.getCredentialEntries().size(); int numActionEntries = response.getActions().size(); int numAuthEntries = response.getAuthenticationActions().size(); - int numRemoteEntry = MetricUtilities.ZERO; - if (response.getRemoteCredentialEntry() != null) { - numRemoteEntry = MetricUtilities.UNIT; - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY); - } - response.getCredentialEntries().forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY)); - response.getActions().forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.ACTION_ENTRY)); - response.getAuthenticationActions().forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.AUTHENTICATION_ENTRY)); - mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCredEntries + numAuthEntries - + numActionEntries + numRemoteEntry); - mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCredEntries); - int numTypes = (response.getCredentialEntries().stream() - .map(CredentialEntry::getType).collect( - Collectors.toSet())).size(); // Dedupe type strings - mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(numTypes); - mCandidatePhasePerProviderMetric.setActionEntryCount(numActionEntries); - mCandidatePhasePerProviderMetric.setAuthenticationEntryCount(numAuthEntries); - mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry); + int numRemoteEntry = response.getRemoteCredentialEntry() != null ? MetricUtilities.ZERO : + MetricUtilities.UNIT; + entryCounts.put(EntryEnum.REMOTE_ENTRY, numRemoteEntry); + entryCounts.put(EntryEnum.CREDENTIAL_ENTRY, numCredEntries); + entryCounts.put(EntryEnum.ACTION_ENTRY, numActionEntries); + entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries); + + response.getCredentialEntries().forEach(entry -> { + String entryKey = generateMetricKey(entry.getType(), DELTA_CUT); + responseCounts.put(entryKey, responseCounts.getOrDefault(entryKey, 0) + 1); + }); + + ResponseCollective responseCollective = new ResponseCollective(responseCounts, entryCounts); + mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective); } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java index 4ecdfef401b6e..b999b301d5cff 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java @@ -272,21 +272,8 @@ public class RequestSessionMetric { candidatePhaseMetric.getStartQueryTimeNanoseconds()); mChosenProviderFinalPhaseMetric.setQueryEndTimeNanoseconds(candidatePhaseMetric .getQueryFinishTimeNanoseconds()); - - mChosenProviderFinalPhaseMetric.setNumEntriesTotal(candidatePhaseMetric - .getNumEntriesTotal()); - mChosenProviderFinalPhaseMetric.setCredentialEntryCount(candidatePhaseMetric - .getCredentialEntryCount()); - mChosenProviderFinalPhaseMetric.setCredentialEntryTypeCount( - candidatePhaseMetric.getCredentialEntryTypeCount()); - mChosenProviderFinalPhaseMetric.setActionEntryCount(candidatePhaseMetric - .getActionEntryCount()); - mChosenProviderFinalPhaseMetric.setRemoteEntryCount(candidatePhaseMetric - .getRemoteEntryCount()); - mChosenProviderFinalPhaseMetric.setAuthenticationEntryCount( - candidatePhaseMetric.getAuthenticationEntryCount()); - mChosenProviderFinalPhaseMetric.setAvailableEntries(candidatePhaseMetric - .getAvailableEntries()); + mChosenProviderFinalPhaseMetric.setResponseCollective( + candidatePhaseMetric.getResponseCollective()); mChosenProviderFinalPhaseMetric.setFinalFinishTimeNanoseconds(System.nanoTime()); } catch (Exception e) { Log.w(TAG, "Unexpected error during metric logging: " + e); diff --git a/services/credentials/java/com/android/server/credentials/metrics/shared/ResponseCollective.java b/services/credentials/java/com/android/server/credentials/metrics/shared/ResponseCollective.java new file mode 100644 index 0000000000000..951aca733b93e --- /dev/null +++ b/services/credentials/java/com/android/server/credentials/metrics/shared/ResponseCollective.java @@ -0,0 +1,128 @@ +/* + * 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.shared; + +import android.annotation.NonNull; +import android.util.Slog; + +import com.android.server.credentials.metrics.EntryEnum; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Some data is directly shared between the + * {@link com.android.server.credentials.metrics.CandidatePhaseMetric} and the + * {@link com.android.server.credentials.metrics.ChosenProviderFinalPhaseMetric}. This + * aims to create an abstraction that holds that information, to avoid duplication. + * + * This class should be immutable and threadsafe once generated. + */ +public class ResponseCollective { + /* + Abstract Function (responseCounts, entryCounts) -> A 'ResponseCollective' containing information + about a chosen or candidate providers available responses, be they entries or credentials. + + RepInvariant: mResponseCounts and mEntryCounts are always initialized + + Threadsafe and Immutability: Once generated, the maps remain unchangeable. The object is + threadsafe and immutable, and safe from external changes. This is threadsafe because it is + immutable after creation and only allows reads, not writes. + */ + + private static final String TAG = "ResponseCollective"; + + // Stores the deduped credential response information, eg {"response":5} for this provider + private final Map mResponseCounts; + // Stores the deduped entry information, eg {ENTRY_ENUM:5} for this provider + private final Map mEntryCounts; + + public ResponseCollective(@NonNull Map responseCounts, + @NonNull Map entryCounts) { + mResponseCounts = responseCounts == null ? new LinkedHashMap<>() : + new LinkedHashMap<>(responseCounts); + mEntryCounts = entryCounts == null ? new LinkedHashMap<>() : + new LinkedHashMap<>(entryCounts); + } + + /** + * Returns the unique, deduped, response classtypes for logging associated with this provider. + * + * @return a string array for deduped classtypes + */ + public String[] getUniqueResponseStrings() { + if (mResponseCounts.isEmpty()) { + Slog.w(TAG, "There are no unique string response types collected"); + } + String[] result = new String[mResponseCounts.keySet().size()]; + mResponseCounts.keySet().toArray(result); + return result; + } + + /** + * Returns the unique, deduped, response classtype counts for logging associated with this + * provider. + * @return a string array for deduped classtype counts + */ + public int[] getUniqueResponseCounts() { + if (mResponseCounts.isEmpty()) { + Slog.w(TAG, "There are no unique string response type counts collected"); + } + return mResponseCounts.values().stream().mapToInt(Integer::intValue).toArray(); + } + + /** + * Returns the unique, deduped, entry types for logging associated with this provider. + * @return an int array for deduped entries + */ + public int[] getUniqueEntries() { + if (mEntryCounts.isEmpty()) { + Slog.w(TAG, "There are no unique entry response types collected"); + } + return mEntryCounts.keySet().stream().mapToInt(Enum::ordinal).toArray(); + } + + /** + * Returns the unique, deduped, entry classtype counts for logging associated with this + * provider. + * @return a string array for deduped classtype counts + */ + public int[] getUniqueEntryCounts() { + if (mEntryCounts.isEmpty()) { + Slog.w(TAG, "There are no unique entry response type counts collected"); + } + return mEntryCounts.values().stream().mapToInt(Integer::intValue).toArray(); + } + + /** + * Given a specific {@link EntryEnum}, this provides us with the count of that entry within + * this particular provider. + * @param e the entry enum with which we want to know the count of + * @return a count of this particular entry enum stored by this provider + */ + public int getCountForEntry(EntryEnum e) { + return mEntryCounts.get(e); + } + + /** + * Indicates the total number of existing entries for this provider. + * @return a count of the total number of entries for this provider + */ + public int getNumEntriesTotal() { + return mEntryCounts.values().stream().mapToInt(Integer::intValue).sum(); + } +}