diff options
9 files changed, 91 insertions, 38 deletions
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java index 04ecd6ebd2d1..e9efe7eb6247 100644 --- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java @@ -19,6 +19,7 @@ package com.android.server.credentials; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; +import android.credentials.ClearCredentialStateException; import android.credentials.ClearCredentialStateRequest; import android.credentials.CredentialProviderInfo; import android.credentials.IClearCredentialStateCallback; @@ -141,8 +142,9 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta return; } } - // TODO: Replace with properly defined error type - respondToClientWithErrorAndFinish("UNKNOWN", "All providers failed"); + String exception = ClearCredentialStateException.TYPE_UNKNOWN; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "All providers failed"); } @Override diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 0af56470965c..d3ea0fee332d 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -141,7 +141,9 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR } else { mRequestSessionMetric.collectChosenProviderStatus( ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode()); - respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS, + String exception = CreateCredentialException.TYPE_NO_CREATE_OPTIONS; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "Invalid response"); } } @@ -154,18 +156,21 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR @Override public void onUiCancellation(boolean isUserCancellation) { - if (isUserCancellation) { - respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_USER_CANCELED, - "User cancelled the selector"); - } else { - respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_INTERRUPTED, - "The UI was interrupted - please try again."); + String exception = CreateCredentialException.TYPE_USER_CANCELED; + String message = "User cancelled the selector"; + if (!isUserCancellation) { + exception = CreateCredentialException.TYPE_INTERRUPTED; + message = "The UI was interrupted - please try again."; } + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, message); } @Override public void onUiSelectorInvocationFailure() { - respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS, + String exception = CreateCredentialException.TYPE_NO_CREATE_OPTIONS; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "No create options available."); } @@ -181,7 +186,9 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR Slog.i(TAG, "Provider status changed - ui invocation is needed"); getProviderDataAndInitiateUi(); } else { - respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS, + String exception = CreateCredentialException.TYPE_NO_CREATE_OPTIONS; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "No create options available."); } } diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index e9fa88328691..aaf760fcfa67 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -106,8 +106,10 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, } catch (RemoteException e) { mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED); + String exception = GetCredentialException.TYPE_UNKNOWN; + mRequestSessionMetric.collectFrameworkException(exception); respondToClientWithErrorAndFinish( - GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector"); + exception, "Unable to instantiate selector"); } } @@ -138,7 +140,9 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, } else { mRequestSessionMetric.collectChosenProviderStatus( ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode()); - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, + String exception = GetCredentialException.TYPE_NO_CREDENTIAL; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "Invalid response from provider"); } } @@ -152,18 +156,21 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, @Override public void onUiCancellation(boolean isUserCancellation) { - if (isUserCancellation) { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_USER_CANCELED, - "User cancelled the selector"); - } else { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_INTERRUPTED, - "The UI was interrupted - please try again."); + String exception = GetCredentialException.TYPE_NO_CREDENTIAL; + String message = "User cancelled the selector"; + if (!isUserCancellation) { + exception = GetCredentialException.TYPE_INTERRUPTED; + message = "The UI was interrupted - please try again."; } + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, message); } @Override public void onUiSelectorInvocationFailure() { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, + String exception = GetCredentialException.TYPE_NO_CREDENTIAL; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "No credentials available."); } @@ -187,7 +194,9 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, Slog.i(TAG, "Provider status changed - ui invocation is needed"); getProviderDataAndInitiateUi(); } else { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, + String exception = GetCredentialException.TYPE_NO_CREDENTIAL; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "No credentials available"); } } @@ -208,7 +217,9 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, // Respond to client if all auth entries are empty and nothing else to show on the UI if (providerDataContainsEmptyAuthEntriesOnly()) { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, + String exception = GetCredentialException.TYPE_NO_CREDENTIAL; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, "No credentials available"); } } diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index e4c6b3a10dd8..40a4bc246889 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -48,12 +48,15 @@ public class MetricUtilities { public static final String DEFAULT_STRING = ""; public static final int[] DEFAULT_REPEATED_INT_32 = new int[0]; public static final String[] DEFAULT_REPEATED_STR = new String[0]; + public static final boolean[] DEFAULT_REPEATED_BOOL = new boolean[0]; // Used for single count metric emits, such as singular amounts of various types public static final int UNIT = 1; // Used for zero count metric emits, such as zero amounts of various types public static final int ZERO = 0; // The number of characters at the end of the string to use as a key - public static final int DELTA_CUT = 20; + public static final int DELTA_RESPONSES_CUT = 20; + // The cut for exception strings from the end - used to keep metrics small + public static final int DELTA_EXCEPTION_CUT = 30; /** * This retrieves the uid of any package name, given a context and a component name for the @@ -165,8 +168,10 @@ public class MetricUtilities { finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(), /* per_classtype_counts */ finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(), - /* framework_exception_unique_classtypes */ - DEFAULT_STRING + /* framework_exception_unique_classtype */ + finalPhaseMetric.getFrameworkException(), + /* primary_indicated */ + false ); } catch (Exception e) { Slog.w(TAG, "Unexpected error during final provider uid emit: " + e); @@ -268,7 +273,9 @@ public class MetricUtilities { /* per_classtype_counts */ initialPhaseMetric.getUniqueRequestCounts(), /* api_name */ - initialPhaseMetric.getApiName() + initialPhaseMetric.getApiName(), + /* primary_candidates_indicated */ + DEFAULT_REPEATED_BOOL ); } catch (Exception e) { Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e); diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java index 27b78a4b7b15..04ddce4a6e60 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java @@ -209,7 +209,6 @@ public abstract class ProviderSession<T, R> isCompletionStatus(status), mProviderSessionUid); mCallbacks.onProviderStatusChanged(status, mComponentName, source); } - /** Common method that transfers metrics from the init phase to candidates */ protected void startCandidateMetrics() { mProviderSessionMetric.collectCandidateMetricSetupViaInitialMetric( 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 3ea9b1ce86f8..cb2e71f8ba9b 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java @@ -53,6 +53,7 @@ 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 framework only exception belonging to this provider private String mFrameworkException = ""; // Stores the response credential information, as well as the response entry information which 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 93a82906aa50..6af686587b88 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java @@ -66,6 +66,8 @@ public class ChosenProviderFinalPhaseMetric { private int mChosenProviderStatus = -1; // Indicates if an exception was thrown by this provider, false by default private boolean mHasException = false; + // Indicates a framework only exception that occurs in the final phase of the flow + private String mFrameworkException = ""; // Stores the response credential information, as well as the response entry information which // by default, contains empty info @@ -272,4 +274,14 @@ public class ChosenProviderFinalPhaseMetric { public ResponseCollective getResponseCollective() { return mResponseCollective; } + + /* -------------- Framework Exception ---------------- */ + + public void setFrameworkException(String frameworkException) { + mFrameworkException = frameworkException; + } + + public String getFrameworkException() { + return mFrameworkException; + } } 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 f011b554fe53..e77636ca3845 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java @@ -16,7 +16,7 @@ package com.android.server.credentials.metrics; -import static com.android.server.credentials.MetricUtilities.DELTA_CUT; +import static com.android.server.credentials.MetricUtilities.DELTA_RESPONSES_CUT; import static com.android.server.credentials.MetricUtilities.generateMetricKey; import android.annotation.NonNull; @@ -170,7 +170,7 @@ public class ProviderSessionMetric { entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries); entries.forEach(entry -> { - String entryKey = generateMetricKey(entry.getType(), DELTA_CUT); + String entryKey = generateMetricKey(entry.getType(), DELTA_RESPONSES_CUT); responseCounts.put(entryKey, responseCounts.getOrDefault(entryKey, 0) + 1); }); @@ -212,7 +212,7 @@ public class ProviderSessionMetric { entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries); response.getCredentialEntries().forEach(entry -> { - String entryKey = generateMetricKey(entry.getType(), DELTA_CUT); + String entryKey = generateMetricKey(entry.getType(), DELTA_RESPONSES_CUT); responseCounts.put(entryKey, responseCounts.getOrDefault(entryKey, 0) + 1); }); 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 4624e0b3701a..4874378a8c21 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java @@ -16,7 +16,8 @@ package com.android.server.credentials.metrics; -import static com.android.server.credentials.MetricUtilities.DELTA_CUT; +import static com.android.server.credentials.MetricUtilities.DELTA_EXCEPTION_CUT; +import static com.android.server.credentials.MetricUtilities.DELTA_RESPONSES_CUT; import static com.android.server.credentials.MetricUtilities.generateMetricKey; import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase; import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPhase; @@ -168,11 +169,9 @@ public class RequestSessionMetric { Map<String, Integer> uniqueRequestCounts = new LinkedHashMap<>(); try { request.getCredentialOptions().forEach(option -> { - String optionKey = generateMetricKey(option.getType(), DELTA_CUT); - if (!uniqueRequestCounts.containsKey(optionKey)) { - uniqueRequestCounts.put(optionKey, 0); - } - uniqueRequestCounts.put(optionKey, uniqueRequestCounts.get(optionKey) + 1); + String optionKey = generateMetricKey(option.getType(), DELTA_RESPONSES_CUT); + uniqueRequestCounts.put(optionKey, uniqueRequestCounts.getOrDefault(optionKey, + 0) + 1); }); } catch (Exception e) { Slog.i(TAG, "Unexpected error during get request metric logging: " + e); @@ -218,7 +217,7 @@ public class RequestSessionMetric { } /** - * Updates the final phase metric with the designated bit + * Updates the final phase metric with the designated bit. * * @param exceptionBitFinalPhase represents if the final phase provider had an exception */ @@ -231,6 +230,21 @@ public class RequestSessionMetric { } /** + * This allows collecting the framework exception string for the final phase metric. + * NOTE that this exception will be cut for space optimizations. + * + * @param exception the framework exception that is being recorded + */ + public void collectFrameworkException(String exception) { + try { + mChosenProviderFinalPhaseMetric.setFrameworkException( + generateMetricKey(exception, DELTA_EXCEPTION_CUT)); + } catch (Exception e) { + Slog.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** * Allows encapsulating the overall final phase metric status from the chosen and final * provider. * @@ -284,7 +298,7 @@ public class RequestSessionMetric { * In the final phase, this helps log use cases that were either pure failures or user * canceled. It's expected that {@link #collectFinalPhaseProviderMetricStatus(boolean, * ProviderStatusForMetrics) collectFinalPhaseProviderMetricStatus} is called prior to this. - * Otherwise, the logging will miss required bits + * Otherwise, the logging will miss required bits. * * @param isUserCanceledError a boolean indicating if the error was due to user cancelling */ |