Merge "Adding Final Phase Exception String to Logs" into udc-dev

This commit is contained in:
Arpan Kaphle
2023-05-08 19:02:17 +00:00
committed by Android (Google) Code Review
9 changed files with 91 additions and 38 deletions

View File

@@ -19,6 +19,7 @@ package com.android.server.credentials;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.credentials.ClearCredentialStateException;
import android.credentials.ClearCredentialStateRequest; import android.credentials.ClearCredentialStateRequest;
import android.credentials.CredentialProviderInfo; import android.credentials.CredentialProviderInfo;
import android.credentials.IClearCredentialStateCallback; import android.credentials.IClearCredentialStateCallback;
@@ -141,8 +142,9 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
return; return;
} }
} }
// TODO: Replace with properly defined error type String exception = ClearCredentialStateException.TYPE_UNKNOWN;
respondToClientWithErrorAndFinish("UNKNOWN", "All providers failed"); mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception, "All providers failed");
} }
@Override @Override

View File

@@ -141,7 +141,9 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
} else { } else {
mRequestSessionMetric.collectChosenProviderStatus( mRequestSessionMetric.collectChosenProviderStatus(
ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode()); ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode());
respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS, String exception = CreateCredentialException.TYPE_NO_CREATE_OPTIONS;
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception,
"Invalid response"); "Invalid response");
} }
} }
@@ -154,18 +156,21 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Override @Override
public void onUiCancellation(boolean isUserCancellation) { public void onUiCancellation(boolean isUserCancellation) {
if (isUserCancellation) { String exception = CreateCredentialException.TYPE_USER_CANCELED;
respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_USER_CANCELED, String message = "User cancelled the selector";
"User cancelled the selector"); if (!isUserCancellation) {
} else { exception = CreateCredentialException.TYPE_INTERRUPTED;
respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_INTERRUPTED, message = "The UI was interrupted - please try again.";
"The UI was interrupted - please try again.");
} }
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception, message);
} }
@Override @Override
public void onUiSelectorInvocationFailure() { 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."); "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"); Slog.i(TAG, "Provider status changed - ui invocation is needed");
getProviderDataAndInitiateUi(); getProviderDataAndInitiateUi();
} else { } else {
respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS, String exception = CreateCredentialException.TYPE_NO_CREATE_OPTIONS;
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception,
"No create options available."); "No create options available.");
} }
} }

View File

@@ -106,8 +106,10 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
} catch (RemoteException e) { } catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED); mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
String exception = GetCredentialException.TYPE_UNKNOWN;
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish( respondToClientWithErrorAndFinish(
GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector"); exception, "Unable to instantiate selector");
} }
} }
@@ -138,7 +140,9 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
} else { } else {
mRequestSessionMetric.collectChosenProviderStatus( mRequestSessionMetric.collectChosenProviderStatus(
ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode()); ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode());
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, String exception = GetCredentialException.TYPE_NO_CREDENTIAL;
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception,
"Invalid response from provider"); "Invalid response from provider");
} }
} }
@@ -152,18 +156,21 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
@Override @Override
public void onUiCancellation(boolean isUserCancellation) { public void onUiCancellation(boolean isUserCancellation) {
if (isUserCancellation) { String exception = GetCredentialException.TYPE_NO_CREDENTIAL;
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_USER_CANCELED, String message = "User cancelled the selector";
"User cancelled the selector"); if (!isUserCancellation) {
} else { exception = GetCredentialException.TYPE_INTERRUPTED;
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_INTERRUPTED, message = "The UI was interrupted - please try again.";
"The UI was interrupted - please try again.");
} }
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception, message);
} }
@Override @Override
public void onUiSelectorInvocationFailure() { public void onUiSelectorInvocationFailure() {
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, String exception = GetCredentialException.TYPE_NO_CREDENTIAL;
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception,
"No credentials available."); "No credentials available.");
} }
@@ -187,7 +194,9 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
Slog.i(TAG, "Provider status changed - ui invocation is needed"); Slog.i(TAG, "Provider status changed - ui invocation is needed");
getProviderDataAndInitiateUi(); getProviderDataAndInitiateUi();
} else { } else {
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, String exception = GetCredentialException.TYPE_NO_CREDENTIAL;
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception,
"No credentials available"); "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 // Respond to client if all auth entries are empty and nothing else to show on the UI
if (providerDataContainsEmptyAuthEntriesOnly()) { if (providerDataContainsEmptyAuthEntriesOnly()) {
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, String exception = GetCredentialException.TYPE_NO_CREDENTIAL;
mRequestSessionMetric.collectFrameworkException(exception);
respondToClientWithErrorAndFinish(exception,
"No credentials available"); "No credentials available");
} }
} }

View File

@@ -48,12 +48,15 @@ public class MetricUtilities {
public static final String DEFAULT_STRING = ""; public static final String DEFAULT_STRING = "";
public static final int[] DEFAULT_REPEATED_INT_32 = new int[0]; public static final int[] DEFAULT_REPEATED_INT_32 = new int[0];
public static final String[] DEFAULT_REPEATED_STR = new String[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 // Used for single count metric emits, such as singular amounts of various types
public static final int UNIT = 1; public static final int UNIT = 1;
// Used for zero count metric emits, such as zero amounts of various types // Used for zero count metric emits, such as zero amounts of various types
public static final int ZERO = 0; public static final int ZERO = 0;
// The number of characters at the end of the string to use as a key // 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 * 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(), finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(),
/* per_classtype_counts */ /* per_classtype_counts */
finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(), finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
/* framework_exception_unique_classtypes */ /* framework_exception_unique_classtype */
DEFAULT_STRING finalPhaseMetric.getFrameworkException(),
/* primary_indicated */
false
); );
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected error during final provider uid emit: " + e); Slog.w(TAG, "Unexpected error during final provider uid emit: " + e);
@@ -268,7 +273,9 @@ public class MetricUtilities {
/* per_classtype_counts */ /* per_classtype_counts */
initialPhaseMetric.getUniqueRequestCounts(), initialPhaseMetric.getUniqueRequestCounts(),
/* api_name */ /* api_name */
initialPhaseMetric.getApiName() initialPhaseMetric.getApiName(),
/* primary_candidates_indicated */
DEFAULT_REPEATED_BOOL
); );
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e); Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e);

View File

@@ -209,7 +209,6 @@ public abstract class ProviderSession<T, R>
isCompletionStatus(status), mProviderSessionUid); isCompletionStatus(status), mProviderSessionUid);
mCallbacks.onProviderStatusChanged(status, mComponentName, source); mCallbacks.onProviderStatusChanged(status, mComponentName, source);
} }
/** Common method that transfers metrics from the init phase to candidates */ /** Common method that transfers metrics from the init phase to candidates */
protected void startCandidateMetrics() { protected void startCandidateMetrics() {
mProviderSessionMetric.collectCandidateMetricSetupViaInitialMetric( mProviderSessionMetric.collectCandidateMetricSetupViaInitialMetric(

View File

@@ -53,6 +53,7 @@ public class CandidatePhaseMetric {
private int mProviderQueryStatus = -1; private int mProviderQueryStatus = -1;
// Indicates if an exception was thrown by this provider, false by default // Indicates if an exception was thrown by this provider, false by default
private boolean mHasException = false; private boolean mHasException = false;
// Indicates the framework only exception belonging to this provider
private String mFrameworkException = ""; private String mFrameworkException = "";
// Stores the response credential information, as well as the response entry information which // Stores the response credential information, as well as the response entry information which

View File

@@ -66,6 +66,8 @@ public class ChosenProviderFinalPhaseMetric {
private int mChosenProviderStatus = -1; private int mChosenProviderStatus = -1;
// Indicates if an exception was thrown by this provider, false by default // Indicates if an exception was thrown by this provider, false by default
private boolean mHasException = false; 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 // Stores the response credential information, as well as the response entry information which
// by default, contains empty info // by default, contains empty info
@@ -272,4 +274,14 @@ public class ChosenProviderFinalPhaseMetric {
public ResponseCollective getResponseCollective() { public ResponseCollective getResponseCollective() {
return mResponseCollective; return mResponseCollective;
} }
/* -------------- Framework Exception ---------------- */
public void setFrameworkException(String frameworkException) {
mFrameworkException = frameworkException;
}
public String getFrameworkException() {
return mFrameworkException;
}
} }

View File

@@ -16,7 +16,7 @@
package com.android.server.credentials.metrics; 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 static com.android.server.credentials.MetricUtilities.generateMetricKey;
import android.annotation.NonNull; import android.annotation.NonNull;
@@ -170,7 +170,7 @@ public class ProviderSessionMetric {
entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries); entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries);
entries.forEach(entry -> { 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); responseCounts.put(entryKey, responseCounts.getOrDefault(entryKey, 0) + 1);
}); });
@@ -212,7 +212,7 @@ public class ProviderSessionMetric {
entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries); entryCounts.put(EntryEnum.AUTHENTICATION_ENTRY, numAuthEntries);
response.getCredentialEntries().forEach(entry -> { 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); responseCounts.put(entryKey, responseCounts.getOrDefault(entryKey, 0) + 1);
}); });

View File

@@ -16,7 +16,8 @@
package com.android.server.credentials.metrics; 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.generateMetricKey;
import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase; import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase;
import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPhase; import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPhase;
@@ -168,11 +169,9 @@ public class RequestSessionMetric {
Map<String, Integer> uniqueRequestCounts = new LinkedHashMap<>(); Map<String, Integer> uniqueRequestCounts = new LinkedHashMap<>();
try { try {
request.getCredentialOptions().forEach(option -> { request.getCredentialOptions().forEach(option -> {
String optionKey = generateMetricKey(option.getType(), DELTA_CUT); String optionKey = generateMetricKey(option.getType(), DELTA_RESPONSES_CUT);
if (!uniqueRequestCounts.containsKey(optionKey)) { uniqueRequestCounts.put(optionKey, uniqueRequestCounts.getOrDefault(optionKey,
uniqueRequestCounts.put(optionKey, 0); 0) + 1);
}
uniqueRequestCounts.put(optionKey, uniqueRequestCounts.get(optionKey) + 1);
}); });
} catch (Exception e) { } catch (Exception e) {
Slog.i(TAG, "Unexpected error during get request metric logging: " + 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 * @param exceptionBitFinalPhase represents if the final phase provider had an exception
*/ */
@@ -230,6 +229,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 * Allows encapsulating the overall final phase metric status from the chosen and final
* provider. * provider.
@@ -284,7 +298,7 @@ public class RequestSessionMetric {
* In the final phase, this helps log use cases that were either pure failures or user * In the final phase, this helps log use cases that were either pure failures or user
* canceled. It's expected that {@link #collectFinalPhaseProviderMetricStatus(boolean, * canceled. It's expected that {@link #collectFinalPhaseProviderMetricStatus(boolean,
* ProviderStatusForMetrics) collectFinalPhaseProviderMetricStatus} is called prior to this. * 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 * @param isUserCanceledError a boolean indicating if the error was due to user cancelling
*/ */