diff options
9 files changed, 233 insertions, 93 deletions
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 793d83e90cfe..4f8235a11b2a 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -168,7 +168,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { Log.i(TAG, "respondToClientWithErrorAndFinish"); - + // TODO add exception bit if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { Log.i(TAG, "Request has already been completed. This is strange."); return; diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 10d3dc030362..3f1a568cce51 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -580,9 +580,13 @@ public final class CredentialManagerService } private void finalizeAndEmitInitialPhaseMetric(RequestSession session) { - var initMetric = session.mInitialPhaseMetric; - initMetric.setCredentialServiceBeginQueryTimeNanoseconds(System.nanoTime()); - MetricUtilities.logApiCalled(initMetric); + try { + var initMetric = session.mInitialPhaseMetric; + initMetric.setCredentialServiceBeginQueryTimeNanoseconds(System.nanoTime()); + MetricUtilities.logApiCalled(initMetric); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } } @Override diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index ed139b57da3d..99f3b3efe838 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -81,6 +81,34 @@ public class MetricUtilities { } /** + * A logging utility used primarily for the candidate phase of the current metric setup. + * + * @param providers a map with known providers + * @param emitSequenceId an emitted sequence id for the current session + */ + protected static void logApiCalled(Map<String, ProviderSession> providers, + int emitSequenceId) { + try { + var providerSessions = providers.values(); + int providerSize = providerSessions.size(); + int[] candidateUidList = new int[providerSize]; + int[] candidateQueryRoundTripTimeList = new int[providerSize]; + int[] candidateStatusList = new int[providerSize]; + int index = 0; + for (var session : providerSessions) { + CandidatePhaseMetric metric = session.mCandidatePhasePerProviderMetric; + candidateUidList[index] = metric.getCandidateUid(); + candidateQueryRoundTripTimeList[index] = metric.getQueryLatencyMicroseconds(); + candidateStatusList[index] = metric.getProviderQueryStatus(); + index++; + } + // TODO Handle the emit here + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** * The most common logging helper, handles the overall status of the API request with the * provider status and latencies. Other versions of this method may be more useful depending * on the situation, as this is geared towards the logging of {@link ProviderSession} types. @@ -90,6 +118,7 @@ public class MetricUtilities { * @param providers a map with known providers * @param callingUid the calling UID of the client app * @param chosenProviderFinalPhaseMetric the metric data type of the final chosen provider + * TODO remove soon */ protected static void logApiCalled(ApiName apiName, ApiStatus apiStatus, Map<String, ProviderSession> providers, int callingUid, @@ -133,6 +162,7 @@ public class MetricUtilities { * contain default values for all other optional parameters. * * TODO(b/271135048) - given space requirements, this may be a good candidate for another atom + * TODO immediately remove and carry over TODO to new log for this setup * * @param apiName the api name to log * @param apiStatus the status to log diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java index 950cf4f9a482..b86dabaa8503 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java @@ -33,7 +33,7 @@ import android.util.Slog; * * @hide */ -public final class ProviderClearSession extends ProviderSession<ClearCredentialStateRequest, +public final class ProviderClearSession extends ProviderSession<ClearCredentialStateRequest, Void> implements RemoteCredentialService.ProviderCallbacks<Void> { @@ -42,7 +42,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredential private ClearCredentialStateException mProviderException; /** Creates a new provider session to be used by the request session. */ - @Nullable public static ProviderClearSession createNewSession( + @Nullable + public static ProviderClearSession createNewSession( Context context, @UserIdInt int userId, CredentialProviderInfo providerInfo, @@ -53,7 +54,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredential clearRequestSession.mClientRequest, clearRequestSession.mClientAppInfo); return new ProviderClearSession(context, providerInfo, clearRequestSession, userId, - remoteCredentialService, providerRequest); + remoteCredentialService, providerRequest); } @Nullable @@ -90,6 +91,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredential if (exception instanceof ClearCredentialStateException) { mProviderException = (ClearCredentialStateException) exception; } + captureCandidateFailure(); updateStatusAndInvokeCallback(toStatus(errorCode)); } @@ -120,14 +122,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredential @Override protected void invokeSession() { if (mRemoteCredentialService != null) { - /* - InitialPhaseMetric initMetric = ((RequestSession)mCallbacks).initMetric; - TODO immediately once the other change patched through - mCandidateProviderMetric.setSessionId(initMetric - .mInitialPhaseMetric.getSessionId()); - mCandidateProviderMetric.setStartTime(initMetric.getStartTime()) - */ - mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); + startCandidateMetrics(); mRemoteCredentialService.onClearCredentialState(mProviderRequest, this); } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java index 3ec0fc0d4646..bbbb15666028 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java @@ -40,6 +40,8 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; +import com.android.server.credentials.metrics.EntryEnum; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -65,7 +67,8 @@ public final class ProviderCreateSession extends ProviderSession< private final ProviderResponseDataHandler mProviderResponseDataHandler; /** Creates a new provider session to be used by the request session. */ - @Nullable public static ProviderCreateSession createNewSession( + @Nullable + public static ProviderCreateSession createNewSession( Context context, @UserIdInt int userId, CredentialProviderInfo providerInfo, @@ -155,6 +158,7 @@ public final class ProviderCreateSession extends ProviderSession< // Store query phase exception for aggregation with final response mProviderException = (CreateCredentialException) exception; } + captureCandidateFailure(); updateStatusAndInvokeCallback(toStatus(errorCode)); } @@ -175,14 +179,32 @@ public final class ProviderCreateSession extends ProviderSession< mProviderResponseDataHandler.addResponseContent(response.getCreateEntries(), response.getRemoteCreateEntry()); if (mProviderResponseDataHandler.isEmptyResponse(response)) { + gatheCandidateEntryMetrics(response); updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE); } else { + gatheCandidateEntryMetrics(response); updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED); } } + private void gatheCandidateEntryMetrics(BeginCreateCredentialResponse response) { + try { + var createEntries = response.getCreateEntries(); + int numCreateEntries = createEntries == null ? 0 : createEntries.size(); + // TODO confirm how to get types from slice + if (numCreateEntries > 0) { + createEntries.forEach(c -> + mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY)); + } + mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCreateEntries); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + @Override - @Nullable protected CreateCredentialProviderData prepareUiData() + @Nullable + protected CreateCredentialProviderData prepareUiData() throws IllegalArgumentException { Log.i(TAG, "In prepareUiData"); if (!ProviderSession.isUiInvokingStatus(getStatus())) { @@ -226,14 +248,7 @@ public final class ProviderCreateSession extends ProviderSession< @Override protected void invokeSession() { if (mRemoteCredentialService != null) { - /* - InitialPhaseMetric initMetric = ((RequestSession)mCallbacks).initMetric; - TODO immediately once the other change patched through - mCandidateProviderMetric.setSessionId(initMetric - .mInitialPhaseMetric.getSessionId()); - mCandidateProviderMetric.setStartTime(initMetric.getStartTime()) - */ - mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); + startCandidateMetrics(); mRemoteCredentialService.onCreateCredential(mProviderRequest, this); } } @@ -305,12 +320,14 @@ public final class ProviderCreateSession extends ProviderSession< } private class ProviderResponseDataHandler { - @Nullable private final ComponentName mExpectedRemoteEntryProviderService; + @Nullable + private final ComponentName mExpectedRemoteEntryProviderService; @NonNull private final Map<String, Pair<CreateEntry, Entry>> mUiCreateEntries = new HashMap<>(); - @Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null; + @Nullable + private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null; ProviderResponseDataHandler(@Nullable ComponentName expectedRemoteEntryProviderService) { mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService; @@ -323,6 +340,7 @@ public final class ProviderCreateSession extends ProviderSession< setRemoteEntry(remoteEntry); } } + public void addCreateEntry(CreateEntry createEntry) { String id = generateUniqueId(); Entry entry = new Entry(SAVE_ENTRY_KEY, @@ -373,6 +391,7 @@ public final class ProviderCreateSession extends ProviderSession< private boolean isEmptyResponse() { return mUiCreateEntries.isEmpty() && mUiRemoteEntry == null; } + @Nullable public RemoteEntry getRemoteEntry(String entryKey) { return mUiRemoteEntry == null || mUiRemoteEntry diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index ec8bf22e4514..bf1db373446b 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -43,6 +43,8 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; +import com.android.server.credentials.metrics.EntryEnum; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -82,7 +84,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential private final ProviderResponseDataHandler mProviderResponseDataHandler; /** Creates a new provider session to be used by the request session. */ - @Nullable public static ProviderGetSession createNewSession( + @Nullable + public static ProviderGetSession createNewSession( Context context, @UserIdInt int userId, CredentialProviderInfo providerInfo, @@ -113,6 +116,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential Log.i(TAG, "Unable to create provider session"); return null; } + private static BeginGetCredentialRequest constructQueryPhaseRequest( android.credentials.GetCredentialRequest filteredRequest, CallingAppInfo callingAppInfo, @@ -169,7 +173,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential CallingAppInfo callingAppInfo, Map<String, CredentialOption> beginGetOptionToCredentialOptionMap, String hybridService) { - super(context, beginGetRequest, callbacks, info.getComponentName() , + super(context, beginGetRequest, callbacks, info.getComponentName(), userId, remoteCredentialService); mCompleteRequest = completeGetRequest; mCallingAppInfo = callingAppInfo; @@ -191,6 +195,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential if (exception instanceof GetCredentialException) { mProviderException = (GetCredentialException) exception; } + captureCandidateFailure(); updateStatusAndInvokeCallback(toStatus(errorCode)); } @@ -269,20 +274,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential @Override protected void invokeSession() { if (mRemoteCredentialService != null) { - /* - InitialPhaseMetric initMetric = ((RequestSession)mCallbacks).initMetric; - TODO immediately once the other change patched through - mCandidateProviderMetric.setSessionId(initMetric - .mInitialPhaseMetric.getSessionId()); - mCandidateProviderMetric.setStartTime(initMetric.getStartTime()) - */ - mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); + startCandidateMetrics(); mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this); } } @Override // Call from request session to data to be shown on the UI - @Nullable protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException { + @Nullable + protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException { Log.i(TAG, "In prepareUiData"); if (!ProviderSession.isUiInvokingStatus(getStatus())) { Log.i(TAG, "In prepareUiData - provider does not want to show UI: " @@ -389,6 +388,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential GetCredentialException exception = maybeGetPendingIntentException( providerPendingIntentResponse); if (exception != null) { + // TODO (b/271135048), for AuthenticationEntry callback selection, set error invokeCallbackWithError(exception.getType(), exception.getMessage()); // Additional content received is in the form of an exception which ends the flow. @@ -439,11 +439,34 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE); return; } - // TODO immediately, add to Candidate Phase counts, repeat across all sessions - // Use sets to dedup type counts + gatherCandidateEntryMetrics(response); updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED); } + private void gatherCandidateEntryMetrics(BeginGetCredentialResponse response) { + try { + int numCredEntries = response.getCredentialEntries().size(); + int numActionEntries = response.getActions().size(); + int numAuthEntries = response.getAuthenticationActions().size(); + // TODO immediately add remote entries + // TODO immediately confirm how to get types from slice to get unique type count via + // dedupe + 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); + mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCredEntries); + mCandidatePhasePerProviderMetric.setActionEntryCount(numActionEntries); + mCandidatePhasePerProviderMetric.setAuthenticationEntryCount(numAuthEntries); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + /** * When an invalid state occurs, e.g. entry mismatch or no response from provider, * we send back a TYPE_NO_CREDENTIAL error as to the developer. @@ -471,11 +494,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential .STATUS_UNLOCKED_BUT_EMPTY_LESS_RECENT || e.second.getStatus() == AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT - ); + ); } private class ProviderResponseDataHandler { - @Nullable private final ComponentName mExpectedRemoteEntryProviderService; + @Nullable + private final ComponentName mExpectedRemoteEntryProviderService; @NonNull private final Map<String, Pair<CredentialEntry, Entry>> mUiCredentialEntries = new HashMap<>(); @@ -485,7 +509,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential private final Map<String, Pair<Action, AuthenticationEntry>> mUiAuthenticationEntries = new HashMap<>(); - @Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null; + @Nullable + private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null; ProviderResponseDataHandler(@Nullable ComponentName expectedRemoteEntryProviderService) { mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService; @@ -509,6 +534,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential setRemoteEntry(remoteEntry); } } + public void addCredentialEntry(CredentialEntry credentialEntry) { String id = generateUniqueId(); Entry entry = new Entry(CREDENTIAL_ENTRY_KEY, @@ -559,7 +585,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential } - public GetCredentialProviderData toGetCredentialProviderData() { return new GetCredentialProviderData.Builder( mComponentName.flattenToString()).setActionChips(prepareActionEntries()) diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java index 77d4e7750038..faa91dce7b92 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java @@ -32,6 +32,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.server.credentials.metrics.CandidatePhaseMetric; +import com.android.server.credentials.metrics.InitialPhaseMetric; import com.android.server.credentials.metrics.ProviderStatusForMetrics; import java.util.UUID; @@ -72,8 +73,9 @@ public abstract class ProviderSession<T, R> @NonNull protected Boolean mProviderResponseSet = false; // Specific candidate provider metric for the provider this session handles - @Nullable - protected CandidatePhaseMetric mCandidatePhasePerProviderMetric; + @NonNull + protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric = + new CandidatePhaseMetric(); @NonNull private int mProviderSessionUid; @@ -143,7 +145,6 @@ public abstract class ProviderSession<T, R> mUserId = userId; mComponentName = componentName; mRemoteCredentialService = remoteCredentialService; - mCandidatePhasePerProviderMetric = new CandidatePhaseMetric(); mProviderSessionUid = MetricUtilities.getPackageUid(mContext, mComponentName); } @@ -208,6 +209,12 @@ public abstract class ProviderSession<T, R> return mRemoteCredentialService; } + protected void captureCandidateFailure() { + mCandidatePhasePerProviderMetric.setHasException(true); + // TODO(b/271135048) - this is a true exception, but what about the empty case? + // Add more nuance in next iteration. + } + /** Updates the status . */ protected void updateStatusAndInvokeCallback(@NonNull Status status) { setStatus(status); @@ -216,18 +223,37 @@ public abstract class ProviderSession<T, R> } private void updateCandidateMetric(Status status) { - mCandidatePhasePerProviderMetric.setCandidateUid(mProviderSessionUid); - // TODO immediately update the candidate phase here to have more new data - mCandidatePhasePerProviderMetric - .setQueryFinishTimeNanoseconds(System.nanoTime()); - if (isTerminatingStatus(status)) { - mCandidatePhasePerProviderMetric.setProviderQueryStatus( - ProviderStatusForMetrics.QUERY_FAILURE - .getMetricCode()); - } else if (isCompletionStatus(status)) { - mCandidatePhasePerProviderMetric.setProviderQueryStatus( - ProviderStatusForMetrics.QUERY_SUCCESS - .getMetricCode()); + try { + mCandidatePhasePerProviderMetric.setCandidateUid(mProviderSessionUid); + // TODO immediately update the candidate phase here to have more new data + mCandidatePhasePerProviderMetric + .setQueryFinishTimeNanoseconds(System.nanoTime()); + if (isTerminatingStatus(status)) { + mCandidatePhasePerProviderMetric.setQueryReturned(false); + mCandidatePhasePerProviderMetric.setProviderQueryStatus( + ProviderStatusForMetrics.QUERY_FAILURE + .getMetricCode()); + } else if (isCompletionStatus(status)) { + mCandidatePhasePerProviderMetric.setQueryReturned(true); + mCandidatePhasePerProviderMetric.setProviderQueryStatus( + ProviderStatusForMetrics.QUERY_SUCCESS + .getMetricCode()); + } + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + // Common method to transfer metrics from the initial phase to the candidate phase per provider + protected void startCandidateMetrics() { + try { + InitialPhaseMetric initMetric = ((RequestSession) mCallbacks).mInitialPhaseMetric; + mCandidatePhasePerProviderMetric.setSessionId(initMetric.getSessionId()); + mCandidatePhasePerProviderMetric.setServiceBeganTimeNanoseconds( + initMetric.getCredentialServiceStartedTimeNanoseconds()); + mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); } } diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index ed42bb2f010a..3ac10c9a7d22 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -19,7 +19,6 @@ package com.android.server.credentials; import static com.android.server.credentials.MetricUtilities.logApiCalled; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; @@ -79,14 +78,14 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan protected final CancellationSignal mCancellationSignal; protected final Map<String, ProviderSession> mProviders = new HashMap<>(); - protected InitialPhaseMetric mInitialPhaseMetric = new InitialPhaseMetric(); - protected ChosenProviderFinalPhaseMetric + protected final InitialPhaseMetric mInitialPhaseMetric = new InitialPhaseMetric(); + protected final ChosenProviderFinalPhaseMetric mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric(); // TODO(b/271135048) - Group metrics used in a scope together, such as here in RequestSession // TODO(b/271135048) - Replace this with a new atom per each browsing emit (V4) - @Nullable - protected List<CandidateBrowsingPhaseMetric> mCandidateBrowsingPhaseMetric; + @NonNull + protected List<CandidateBrowsingPhaseMetric> mCandidateBrowsingPhaseMetric = new ArrayList<>(); // As emits occur in sequential order, increment this counter and utilize protected int mSequenceCounter = 0; protected final String mHybridService; @@ -124,9 +123,17 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan mUserId, this); mHybridService = context.getResources().getString( R.string.config_defaultCredentialManagerHybridService); - mInitialPhaseMetric.setCredentialServiceStartedTimeNanoseconds(timestampStarted); - mInitialPhaseMetric.setSessionId(mRequestId.hashCode()); - mInitialPhaseMetric.setCallerUid(mCallingUid); + initialPhaseMetricSetup(timestampStarted); + } + + private void initialPhaseMetricSetup(long timestampStarted) { + try { + mInitialPhaseMetric.setCredentialServiceStartedTimeNanoseconds(timestampStarted); + mInitialPhaseMetric.setSessionId(mRequestId.hashCode()); + mInitialPhaseMetric.setCallerUid(mCallingUid); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } } public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo, @@ -171,13 +178,17 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan private void logBrowsingPhasePerSelect(UserSelectionDialogResult selection, ProviderSession providerSession) { - CandidateBrowsingPhaseMetric browsingPhaseMetric = new CandidateBrowsingPhaseMetric(); - browsingPhaseMetric.setSessionId(this.mInitialPhaseMetric.getSessionId()); - browsingPhaseMetric.setEntryEnum( - EntryEnum.getMetricCodeFromString(selection.getEntryKey())); - browsingPhaseMetric.setProviderUid(providerSession.mCandidatePhasePerProviderMetric - .getCandidateUid()); - this.mCandidateBrowsingPhaseMetric.add(new CandidateBrowsingPhaseMetric()); + try { + CandidateBrowsingPhaseMetric browsingPhaseMetric = new CandidateBrowsingPhaseMetric(); + browsingPhaseMetric.setSessionId(this.mInitialPhaseMetric.getSessionId()); + browsingPhaseMetric.setEntryEnum( + EntryEnum.getMetricCodeFromString(selection.getEntryKey())); + browsingPhaseMetric.setProviderUid(providerSession.mCandidatePhasePerProviderMetric + .getCandidateUid()); + this.mCandidateBrowsingPhaseMetric.add(new CandidateBrowsingPhaseMetric()); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } } protected void finishSession(boolean propagateCancellation) { @@ -234,6 +245,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size()); if (isSessionCancelled()) { + MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter); finishSession(/*propagateCancellation=*/true); return; } @@ -249,13 +261,8 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan } if (!providerDataList.isEmpty()) { Log.i(TAG, "provider list not empty about to initiate ui"); - // TODO immediately Add paths to end it (say it fails) - if (isSessionCancelled()) { - Log.i(TAG, "In getProviderDataAndInitiateUi but session has been cancelled"); - // TODO immedaitely Add paths - } else { - launchUiWithProviderData(providerDataList); - } + MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter); + launchUiWithProviderData(providerDataList); } } @@ -265,22 +272,27 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan * @param componentName the componentName to associate with a provider */ protected void setChosenMetric(ComponentName componentName) { - CandidatePhaseMetric metric = this.mProviders.get(componentName.flattenToString()) - .mCandidatePhasePerProviderMetric; + try { + CandidatePhaseMetric metric = this.mProviders.get(componentName.flattenToString()) + .mCandidatePhasePerProviderMetric; - mChosenProviderFinalPhaseMetric.setSessionId(metric.getSessionId()); - mChosenProviderFinalPhaseMetric.setChosenUid(metric.getCandidateUid()); + mChosenProviderFinalPhaseMetric.setSessionId(metric.getSessionId()); + mChosenProviderFinalPhaseMetric.setChosenUid(metric.getCandidateUid()); - mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds( - metric.getQueryLatencyMicroseconds()); + mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds( + metric.getQueryLatencyMicroseconds()); - mChosenProviderFinalPhaseMetric.setServiceBeganTimeNanoseconds( - metric.getServiceBeganTimeNanoseconds()); - mChosenProviderFinalPhaseMetric.setQueryStartTimeNanoseconds( - metric.getStartQueryTimeNanoseconds()); + mChosenProviderFinalPhaseMetric.setServiceBeganTimeNanoseconds( + metric.getServiceBeganTimeNanoseconds()); + mChosenProviderFinalPhaseMetric.setQueryStartTimeNanoseconds( + metric.getStartQueryTimeNanoseconds()); - // TODO immediately update with the entry count numbers from the candidate metrics + // TODO immediately update with the entry count numbers from the candidate metrics + // TODO immediately add the exception bit for candidates and providers - mChosenProviderFinalPhaseMetric.setFinalFinishTimeNanoseconds(System.nanoTime()); + 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/CandidatePhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java index c392d7806910..f00c7f46c5ae 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java @@ -20,6 +20,9 @@ import android.util.Log; import com.android.server.credentials.MetricUtilities; +import java.util.ArrayList; +import java.util.List; + /** * The central candidate provider metric object that mimics our defined metric setup. * Some types are redundant across these metric collectors, but that has debug use-cases as @@ -66,6 +69,8 @@ public class CandidatePhaseMetric { 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<EntryEnum> mAvailableEntries = new ArrayList<>(); public CandidatePhaseMetric() { } @@ -236,4 +241,28 @@ public class CandidatePhaseMetric { 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) { + this.mAvailableEntries.add(e); + } + + /** + * 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<EntryEnum> getAvailableEntries() { + return new ArrayList<>(this.mAvailableEntries); // no alias copy + } } |