summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/credentials/java/com/android/server/credentials/ClearRequestSession.java11
-rw-r--r--services/credentials/java/com/android/server/credentials/CreateRequestSession.java10
-rw-r--r--services/credentials/java/com/android/server/credentials/GetRequestSession.java10
-rw-r--r--services/credentials/java/com/android/server/credentials/MetricUtilities.java145
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderCreateSession.java4
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderGetSession.java5
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderSession.java14
-rw-r--r--services/credentials/java/com/android/server/credentials/RequestSession.java9
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/BrowsedAuthenticationMetric.java36
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidateAggregateMetric.java75
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java12
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java15
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java26
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java15
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java42
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java55
16 files changed, 405 insertions, 79 deletions
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index e9efe7eb6247..e3d4c224f1fd 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -30,6 +30,8 @@ import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
import android.util.Slog;
+import com.android.server.credentials.metrics.ProviderSessionMetric;
+
import java.util.ArrayList;
import java.util.Set;
@@ -93,9 +95,12 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
public void onFinalResponseReceived(
ComponentName componentName,
Void response) {
- mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(
- mProviders.get(componentName.flattenToString()).mProviderSessionMetric
- .getCandidatePhasePerProviderMetric());
+ if (mProviders.get(componentName.flattenToString()) != null) {
+ ProviderSessionMetric providerSessionMetric =
+ mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
+ mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
+ .getCandidatePhasePerProviderMetric());
+ }
respondToClientWithResponseAndFinish(null);
}
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index d3ea0fee332d..2d6e74f0ccf1 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -35,6 +35,7 @@ import android.service.credentials.CallingAppInfo;
import android.service.credentials.PermissionUtils;
import android.util.Slog;
+import com.android.server.credentials.metrics.ProviderSessionMetric;
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import java.util.ArrayList;
@@ -131,9 +132,12 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Nullable CreateCredentialResponse response) {
Slog.i(TAG, "Final credential received from: " + componentName.flattenToString());
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime());
- mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(mProviders.get(
- componentName.flattenToString()).mProviderSessionMetric
- .getCandidatePhasePerProviderMetric());
+ if (mProviders.get(componentName.flattenToString()) != null) {
+ ProviderSessionMetric providerSessionMetric =
+ mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
+ mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
+ .getCandidatePhasePerProviderMetric());
+ }
if (response != null) {
mRequestSessionMetric.collectChosenProviderStatus(
ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode());
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index aaf760fcfa67..9eb3b3b5b7cd 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -32,6 +32,7 @@ import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
import android.util.Slog;
+import com.android.server.credentials.metrics.ProviderSessionMetric;
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import java.util.ArrayList;
@@ -130,9 +131,12 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
@Nullable GetCredentialResponse response) {
Slog.i(TAG, "onFinalResponseReceived from: " + componentName.flattenToString());
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime());
- mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(
- mProviders.get(componentName.flattenToString())
- .mProviderSessionMetric.getCandidatePhasePerProviderMetric());
+ if (mProviders.get(componentName.flattenToString()) != null) {
+ ProviderSessionMetric providerSessionMetric =
+ mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
+ mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
+ .getCandidatePhasePerProviderMetric());
+ }
if (response != null) {
mRequestSessionMetric.collectChosenProviderStatus(
ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode());
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index 40a4bc246889..f9c44a94f89b 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -24,12 +24,14 @@ import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ApiStatus;
+import com.android.server.credentials.metrics.CandidateAggregateMetric;
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.security.SecureRandom;
import java.util.List;
import java.util.Map;
@@ -79,6 +81,15 @@ public class MetricUtilities {
}
/**
+ * Used to help generate random sequences for local sessions, in the time-scale of credential
+ * manager flows.
+ * @return a high entropy int useful to use in reasonable time-frame sessions.
+ */
+ public static int getHighlyUniqueInteger() {
+ return new SecureRandom().nextInt();
+ }
+
+ /**
* Given any two timestamps in nanoseconds, this gets the difference and converts to
* milliseconds. Assumes the difference is not larger than the maximum int size.
*
@@ -130,7 +141,7 @@ public class MetricUtilities {
index++;
}
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_FINAL_PHASE_REPORTED,
- /* session_id */ finalPhaseMetric.getSessionId(),
+ /* session_id */ finalPhaseMetric.getSessionIdProvider(),
/* sequence_num */ emitSequenceId,
/* ui_returned_final_start */ finalPhaseMetric.isUiReturned(),
/* chosen_provider_uid */ finalPhaseMetric.getChosenUid(),
@@ -170,8 +181,7 @@ public class MetricUtilities {
finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
/* framework_exception_unique_classtype */
finalPhaseMetric.getFrameworkException(),
- /* primary_indicated */
- false
+ /* primary_indicated */ false
);
} catch (Exception e) {
Slog.w(TAG, "Unexpected error during final provider uid emit: " + e);
@@ -215,7 +225,7 @@ public class MetricUtilities {
CandidatePhaseMetric metric = session.mProviderSessionMetric
.getCandidatePhasePerProviderMetric();
if (sessionId == -1) {
- sessionId = metric.getSessionId();
+ sessionId = metric.getSessionIdProvider();
}
if (!queryReturned) {
queryReturned = metric.isQueryReturned();
@@ -319,7 +329,7 @@ public class MetricUtilities {
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_INIT_PHASE_REPORTED,
/* api_name */ initialPhaseMetric.getApiName(),
/* caller_uid */ initialPhaseMetric.getCallerUid(),
- /* session_id */ initialPhaseMetric.getSessionId(),
+ /* session_id */ initialPhaseMetric.getSessionIdCaller(),
/* sequence_num */ sequenceNum,
/* initial_timestamp_reference_nanoseconds */
initialPhaseMetric.getCredentialServiceStartedTimeNanoseconds(),
@@ -336,4 +346,129 @@ public class MetricUtilities {
Slog.w(TAG, "Unexpected error during initial metric emit: " + e);
}
}
+
+ /**
+ * A logging utility focused on track 1, where the calling app is known. This captures all
+ * aggregate information for the candidate phase.
+ *
+ * @param candidateAggregateMetric the aggregate candidate metric information collected
+ * @param sequenceNum the sequence number for this api call session emit
+ */
+ public static void logApiCalledAggregateCandidate(
+ CandidateAggregateMetric candidateAggregateMetric,
+ int sequenceNum) {
+ try {
+ if (!LOG_FLAG) {
+ FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_TOTAL_REPORTED,
+ /*session_id*/ candidateAggregateMetric.getSessionIdProvider(),
+ /*sequence_num*/ sequenceNum,
+ /*query_returned*/ candidateAggregateMetric.isQueryReturned(),
+ /*num_providers*/ candidateAggregateMetric.getNumProviders(),
+ /*min_query_start_timestamp_microseconds*/
+ DEFAULT_INT_32,
+ /*max_query_end_timestamp_microseconds*/
+ DEFAULT_INT_32,
+ /*query_response_unique_classtypes*/
+ DEFAULT_REPEATED_STR,
+ /*query_per_classtype_counts*/
+ DEFAULT_REPEATED_INT_32,
+ /*query_unique_entries*/
+ DEFAULT_REPEATED_INT_32,
+ /*query_per_entry_counts*/
+ DEFAULT_REPEATED_INT_32,
+ /*query_total_candidate_failure*/
+ DEFAULT_INT_32,
+ /*query_framework_exception_unique_classtypes*/
+ DEFAULT_REPEATED_STR,
+ /*query_per_exception_classtype_counts*/
+ DEFAULT_REPEATED_INT_32,
+ /*auth_response_unique_classtypes*/
+ DEFAULT_REPEATED_STR,
+ /*auth_per_classtype_counts*/
+ DEFAULT_REPEATED_INT_32,
+ /*auth_unique_entries*/
+ DEFAULT_REPEATED_INT_32,
+ /*auth_per_entry_counts*/
+ DEFAULT_REPEATED_INT_32,
+ /*auth_total_candidate_failure*/
+ DEFAULT_INT_32,
+ /*auth_framework_exception_unique_classtypes*/
+ DEFAULT_REPEATED_STR,
+ /*auth_per_exception_classtype_counts*/
+ DEFAULT_REPEATED_INT_32,
+ /*num_auth_clicks*/
+ DEFAULT_INT_32,
+ /*auth_returned*/ false
+ );
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Unexpected error during metric logging: " + e);
+ }
+ }
+
+ /**
+ * A logging utility used primarily for the final phase of the current metric setup for track 1.
+ *
+ * @param finalPhaseMetric the coalesced data of the chosen provider
+ * @param browsingPhaseMetrics the coalesced data of the browsing phase
+ * @param apiStatus the final status of this particular api call
+ * @param emitSequenceId an emitted sequence id for the current session
+ */
+ public static void logApiCalledNoUidFinal(ChosenProviderFinalPhaseMetric finalPhaseMetric,
+ List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus,
+ int emitSequenceId) {
+ try {
+ if (!LOG_FLAG) {
+ return;
+ }
+ int browsedSize = browsingPhaseMetrics.size();
+ int[] browsedClickedEntries = new int[browsedSize];
+ int[] browsedProviderUid = new int[browsedSize];
+ int index = 0;
+ for (CandidateBrowsingPhaseMetric metric : browsingPhaseMetrics) {
+ browsedClickedEntries[index] = metric.getEntryEnum();
+ browsedProviderUid[index] = metric.getProviderUid();
+ index++;
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_FINALNOUID_REPORTED,
+ /* session_id */ finalPhaseMetric.getSessionIdCaller(),
+ /* sequence_num */ emitSequenceId,
+ /* ui_returned_final_start */ finalPhaseMetric.isUiReturned(),
+ /* chosen_provider_query_start_timestamp_microseconds */
+ finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
+ .getQueryStartTimeNanoseconds()),
+ /* chosen_provider_query_end_timestamp_microseconds */
+ finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
+ .getQueryEndTimeNanoseconds()),
+ /* chosen_provider_ui_invoked_timestamp_microseconds */
+ finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
+ .getUiCallStartTimeNanoseconds()),
+ /* chosen_provider_ui_finished_timestamp_microseconds */
+ finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
+ .getUiCallEndTimeNanoseconds()),
+ /* chosen_provider_finished_timestamp_microseconds */
+ finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
+ .getFinalFinishTimeNanoseconds()),
+ /* chosen_provider_status */ finalPhaseMetric.getChosenProviderStatus(),
+ /* chosen_provider_has_exception */ finalPhaseMetric.isHasException(),
+ /* 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_classtype */
+ finalPhaseMetric.getFrameworkException(),
+ /* clicked_entries */ browsedClickedEntries,
+ /* provider_of_clicked_entry */ browsedProviderUid,
+ /* api_status */ apiStatus,
+ /* primary_indicated */ false
+ );
+ } catch (Exception e) {
+ Slog.w(TAG, "Unexpected error during metric logging: " + e);
+ }
+ }
+
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 409806a21679..25f20caee16d 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -193,11 +193,11 @@ public final class ProviderCreateSession extends ProviderSession<
mProviderResponseDataHandler.addResponseContent(response.getCreateEntries(),
response.getRemoteCreateEntry());
if (mProviderResponseDataHandler.isEmptyResponse(response)) {
- mProviderSessionMetric.collectCandidateEntryMetrics(response);
+ mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE,
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
} else {
- mProviderSessionMetric.collectCandidateEntryMetrics(response);
+ mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED,
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 64438e338e5b..51af25b58992 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -433,6 +433,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
BeginGetCredentialResponse response = PendingIntentResultHandler
.extractResponseContent(providerPendingIntentResponse
.getResultData());
+ mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/true);
if (response != null && !mProviderResponseDataHandler.isEmptyResponse(response)) {
addToInitialRemoteResponse(response, /*isInitialResponse=*/ false);
// Additional content received is in the form of new response content.
@@ -470,12 +471,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
addToInitialRemoteResponse(response, /*isInitialResponse=*/true);
// Log the data.
if (mProviderResponseDataHandler.isEmptyResponse(response)) {
- mProviderSessionMetric.collectCandidateEntryMetrics(response);
+ mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE,
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
return;
}
- mProviderSessionMetric.collectCandidateEntryMetrics(response);
+ mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED,
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 04ddce4a6e60..068ca7928117 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -71,7 +71,7 @@ public abstract class ProviderSession<T, R>
@NonNull
protected Boolean mProviderResponseSet = false;
@NonNull
- protected final ProviderSessionMetric mProviderSessionMetric = new ProviderSessionMetric();
+ protected final ProviderSessionMetric mProviderSessionMetric;
@NonNull
private int mProviderSessionUid;
@@ -114,6 +114,13 @@ public abstract class ProviderSession<T, R>
}
/**
+ * Gives access to the objects metric collectors.
+ */
+ public ProviderSessionMetric getProviderSessionMetric() {
+ return this.mProviderSessionMetric;
+ }
+
+ /**
* Interface to be implemented by any class that wishes to get a callback when a particular
* provider session's status changes. Typically, implemented by the {@link RequestSession}
* class.
@@ -147,6 +154,8 @@ public abstract class ProviderSession<T, R>
mComponentName = componentName;
mRemoteCredentialService = remoteCredentialService;
mProviderSessionUid = MetricUtilities.getPackageUid(mContext, mComponentName);
+ mProviderSessionMetric = new ProviderSessionMetric(
+ ((RequestSession) mCallbacks).mRequestSessionMetric.getSessionIdTrackTwo());
}
/** Provider status at various states of the provider session. */
@@ -206,7 +215,8 @@ public abstract class ProviderSession<T, R>
CredentialsSource source) {
setStatus(status);
mProviderSessionMetric.collectCandidateMetricUpdate(isTerminatingStatus(status),
- isCompletionStatus(status), mProviderSessionUid);
+ isCompletionStatus(status), mProviderSessionUid,
+ source == CredentialsSource.AUTH_ENTRY);
mCallbacks.onProviderStatusChanged(status, mComponentName, source);
}
/** Common method that transfers metrics from the init phase to candidates */
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 7caa921eacda..a41b5713ee14 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -75,6 +75,8 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
protected final Handler mHandler;
@UserIdInt
protected final int mUserId;
+
+ protected final int mUniqueSessionInteger;
private final int mCallingUid;
@NonNull
protected final CallingAppInfo mClientAppInfo;
@@ -82,7 +84,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
protected final CancellationSignal mCancellationSignal;
protected final Map<String, ProviderSession> mProviders = new ConcurrentHashMap<>();
- protected final RequestSessionMetric mRequestSessionMetric = new RequestSessionMetric();
+ protected final RequestSessionMetric mRequestSessionMetric;
protected final String mHybridService;
protected final Object mLock;
@@ -132,7 +134,10 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
mUserId, this, mEnabledProviders);
mHybridService = context.getResources().getString(
R.string.config_defaultCredentialManagerHybridService);
- mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId,
+ mUniqueSessionInteger = MetricUtilities.getHighlyUniqueInteger();
+ mRequestSessionMetric = new RequestSessionMetric(mUniqueSessionInteger,
+ MetricUtilities.getHighlyUniqueInteger());
+ mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted,
mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
setCancellationListener();
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/BrowsedAuthenticationMetric.java b/services/credentials/java/com/android/server/credentials/metrics/BrowsedAuthenticationMetric.java
new file mode 100644
index 000000000000..51e86d51acdf
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/metrics/BrowsedAuthenticationMetric.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Encapsulates an authentication entry click atom, as a part of track 2.
+ * Contains information about what was collected from the authentication entry output.
+ */
+public class BrowsedAuthenticationMetric {
+ // The session id of this provider known flow related metric
+ private final int mSessionIdProvider;
+ // TODO(b/271135048) - Match the atom and provide a clean per provider session metric
+ // encapsulation.
+
+ public BrowsedAuthenticationMetric(int sessionIdProvider) {
+ mSessionIdProvider = sessionIdProvider;
+ }
+
+ public int getSessionIdProvider() {
+ return mSessionIdProvider;
+ }
+}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidateAggregateMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidateAggregateMetric.java
new file mode 100644
index 000000000000..08e75837a274
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidateAggregateMetric.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.credentials.metrics;
+
+import com.android.server.credentials.ProviderSession;
+
+import java.util.Map;
+
+/**
+ * This will generate most of its data via using the information of {@link CandidatePhaseMetric}
+ * across all the providers. This belongs to the metric flow where the calling app is known.
+ */
+public class CandidateAggregateMetric {
+
+ private static final String TAG = "CandidateProviderMetric";
+ // The session id of this provider metric
+ private final int mSessionIdProvider;
+ // Indicates if this provider returned from the query phase, default false
+ private boolean mQueryReturned = false;
+ // Indicates the total number of providers this aggregate captures information for, default 0
+ private int mNumProviders = 0;
+ // Indicates the total number of authentication entries that were tapped in aggregate, default 0
+ private int mNumAuthEntriesTapped = 0;
+
+ public CandidateAggregateMetric(int sessionIdTrackOne) {
+ mSessionIdProvider = sessionIdTrackOne;
+ }
+
+ public int getSessionIdProvider() {
+ return mSessionIdProvider;
+ }
+
+ /**
+ * This will take all the candidate data captured and aggregate that information.
+ * TODO(b/271135048) : Add on authentication entry outputs from track 2 here as well once
+ * generated
+ * @param providers the providers associated with the candidate flow
+ */
+ public void collectAverages(Map<String, ProviderSession> providers) {
+ // TODO(b/271135048) : Complete this method
+ mNumProviders = providers.size();
+ var providerSessions = providers.values();
+ for (var session : providerSessions) {
+ var metric = session.getProviderSessionMetric();
+ mQueryReturned = mQueryReturned || metric
+ .mCandidatePhasePerProviderMetric.isQueryReturned();
+ }
+ }
+
+ public int getNumProviders() {
+ return mNumProviders;
+ }
+
+ public boolean isQueryReturned() {
+ return mQueryReturned;
+ }
+
+ public int getNumAuthEntriesTapped() {
+ return mNumAuthEntriesTapped;
+ }
+}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
index 07af6549411e..6b74252dec19 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
@@ -27,23 +27,11 @@ package com.android.server.credentials.metrics;
* though collection will begin in the candidate phase when the user begins browsing options.
*/
public class CandidateBrowsingPhaseMetric {
- // The session id associated with the API Call this candidate provider is a part of, default -1
- private int mSessionId = -1;
// The EntryEnum that was pressed, defaults to -1
private int mEntryEnum = EntryEnum.UNKNOWN.getMetricCode();
// The provider associated with the press, defaults to -1
private int mProviderUid = -1;
- /* -- The session ID -- */
-
- public void setSessionId(int sessionId) {
- mSessionId = sessionId;
- }
-
- public int getSessionId() {
- return mSessionId;
- }
-
/* -- The Entry of this tap -- */
public void setEntryEnum(int entryEnum) {
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 cb2e71f8ba9b..d9bf4a134adb 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
@@ -32,8 +32,8 @@ import java.util.Map;
public class CandidatePhaseMetric {
private static final String TAG = "CandidateProviderMetric";
- // The session id of this provider, default set to -1
- private int mSessionId = -1;
+ // The session id of this provider metric
+ private final int mSessionIdProvider;
// Indicates if this provider returned from the query phase, default false
private boolean mQueryReturned = false;
@@ -60,7 +60,8 @@ public class CandidatePhaseMetric {
// by default, contains empty info
private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
- public CandidatePhaseMetric() {
+ public CandidatePhaseMetric(int sessionIdTrackTwo) {
+ mSessionIdProvider = sessionIdTrackTwo;
}
/* ---------- Latencies ---------- */
@@ -142,12 +143,8 @@ public class CandidatePhaseMetric {
/* -------------- Session Id ---------------- */
- public void setSessionId(int sessionId) {
- mSessionId = sessionId;
- }
-
- public int getSessionId() {
- return mSessionId;
+ public int getSessionIdProvider() {
+ return mSessionIdProvider;
}
/* -------------- Query Returned Status ---------------- */
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 6af686587b88..e8af86012aaf 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
@@ -32,8 +32,12 @@ import java.util.Map;
*/
public class ChosenProviderFinalPhaseMetric {
private static final String TAG = "ChosenFinalPhaseMetric";
- // The session id associated with this API call, used to unite split emits
- private int mSessionId = -1;
+ // The session id associated with this API call, used to unite split emits, for the flow
+ // where we know the calling app
+ private final int mSessionIdCaller;
+ // The session id associated with this API call, used to unite split emits, for the flow
+ // where we know the provider apps
+ private final int mSessionIdProvider;
// Reveals if the UI was returned, false by default
private boolean mUiReturned = false;
private int mChosenUid = -1;
@@ -74,7 +78,9 @@ public class ChosenProviderFinalPhaseMetric {
private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
- public ChosenProviderFinalPhaseMetric() {
+ public ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider) {
+ mSessionIdCaller = sessionIdCaller;
+ mSessionIdProvider = sessionIdProvider;
}
/* ------------------- UID ------------------- */
@@ -237,12 +243,8 @@ public class ChosenProviderFinalPhaseMetric {
/* ----------- Session ID -------------- */
- public void setSessionId(int sessionId) {
- mSessionId = sessionId;
- }
-
- public int getSessionId() {
- return mSessionId;
+ public int getSessionIdProvider() {
+ return mSessionIdProvider;
}
/* ----------- UI Returned Successfully -------------- */
@@ -284,4 +286,10 @@ public class ChosenProviderFinalPhaseMetric {
public String getFrameworkException() {
return mFrameworkException;
}
+
+ /* -------------- Session ID for Track One (Known Calling App) ---------------- */
+
+ public int getSessionIdCaller() {
+ return mSessionIdCaller;
+ }
}
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 060e56ce965b..8e965e3e5ba5 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
@@ -32,8 +32,8 @@ public class InitialPhaseMetric {
private int mApiName = ApiName.UNKNOWN.getMetricCode();
// The caller uid of the calling application, default to -1
private int mCallerUid = -1;
- // The session id to unite multiple atom emits, default to -1
- private int mSessionId = -1;
+ // The session id to unite multiple atom emits
+ private final int mSessionIdCaller;
// Raw timestamps in nanoseconds, *the only* one logged as such (i.e. 64 bits) since it is a
// reference point.
@@ -50,7 +50,8 @@ public class InitialPhaseMetric {
private Map<String, Integer> mRequestCounts = new LinkedHashMap<>();
- public InitialPhaseMetric() {
+ public InitialPhaseMetric(int sessionIdTrackOne) {
+ mSessionIdCaller = sessionIdTrackOne;
}
/* ---------- Latencies ---------- */
@@ -105,12 +106,8 @@ public class InitialPhaseMetric {
/* ------ SessionId ------ */
- public void setSessionId(int sessionId) {
- mSessionId = sessionId;
- }
-
- public int getSessionId() {
- return mSessionId;
+ public int getSessionIdCaller() {
+ return mSessionIdCaller;
}
/* ------ Count Request Class Types ------ */
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 e77636ca3845..47db8f59ff35 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
@@ -44,10 +44,17 @@ public class ProviderSessionMetric {
// Specific candidate provider metric for the provider this session handles
@NonNull
- protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric =
- new CandidatePhaseMetric();
+ protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric;
- public ProviderSessionMetric() {}
+ // IFF there was an authentication entry clicked, this stores all required information for
+ // that event. This is for the 'get' flow.
+ @NonNull
+ protected final BrowsedAuthenticationMetric mBrowsedAuthenticationMetric;
+
+ public ProviderSessionMetric(int sessionIdTrackTwo) {
+ mCandidatePhasePerProviderMetric = new CandidatePhaseMetric(sessionIdTrackTwo);
+ mBrowsedAuthenticationMetric = new BrowsedAuthenticationMetric(sessionIdTrackTwo);
+ }
/**
* Retrieve the candidate provider phase metric and the data it contains.
@@ -56,6 +63,7 @@ public class ProviderSessionMetric {
return mCandidatePhasePerProviderMetric;
}
+
/**
* This collects for ProviderSessions, with respect to the candidate providers, whether
* an exception occurred in the candidate call.
@@ -78,6 +86,13 @@ public class ProviderSessionMetric {
}
}
+ private void collectAuthEntryUpdate(boolean isFailureStatus,
+ boolean isCompletionStatus, int providerSessionUid) {
+ // TODO(b/271135048) - Mimic typical candidate update, but with authentication metric
+ // Collect the final timestamps (and start timestamp), status, exceptions and the provider
+ // uid. This occurs typically *after* the collection is complete.
+ }
+
/**
* Used to collect metrics at the update stage when a candidate provider gives back an update.
*
@@ -86,8 +101,12 @@ public class ProviderSessionMetric {
* @param providerSessionUid the uid of the provider
*/
public void collectCandidateMetricUpdate(boolean isFailureStatus,
- boolean isCompletionStatus, int providerSessionUid) {
+ boolean isCompletionStatus, int providerSessionUid, boolean isAuthEntry) {
try {
+ if (isAuthEntry) {
+ collectAuthEntryUpdate(isFailureStatus, isCompletionStatus, providerSessionUid);
+ return;
+ }
mCandidatePhasePerProviderMetric.setCandidateUid(providerSessionUid);
mCandidatePhasePerProviderMetric
.setQueryFinishTimeNanoseconds(System.nanoTime());
@@ -119,7 +138,6 @@ public class ProviderSessionMetric {
*/
public void collectCandidateMetricSetupViaInitialMetric(InitialPhaseMetric initMetric) {
try {
- mCandidatePhasePerProviderMetric.setSessionId(initMetric.getSessionId());
mCandidatePhasePerProviderMetric.setServiceBeganTimeNanoseconds(
initMetric.getCredentialServiceStartedTimeNanoseconds());
mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime());
@@ -133,13 +151,14 @@ public class ProviderSessionMetric {
* purposes.
*
* @param response contains entries and data from the candidate provider responses
+ * @param isAuthEntry indicates if this is an auth entry collection or not
* @param <R> the response type associated with the API flow in progress
*/
- public <R> void collectCandidateEntryMetrics(R response) {
+ public <R> void collectCandidateEntryMetrics(R response, boolean isAuthEntry) {
try {
if (response instanceof BeginGetCredentialResponse) {
beginGetCredentialResponseCollectionCandidateEntryMetrics(
- (BeginGetCredentialResponse) response);
+ (BeginGetCredentialResponse) response, isAuthEntry);
} else if (response instanceof BeginCreateCredentialResponse) {
beginCreateCredentialResponseCollectionCandidateEntryMetrics(
(BeginCreateCredentialResponse) response);
@@ -198,7 +217,7 @@ public class ProviderSessionMetric {
}
private void beginGetCredentialResponseCollectionCandidateEntryMetrics(
- BeginGetCredentialResponse response) {
+ BeginGetCredentialResponse response, boolean isAuthEntry) {
Map<EntryEnum, Integer> entryCounts = new LinkedHashMap<>();
Map<String, Integer> responseCounts = new LinkedHashMap<>();
int numCredEntries = response.getCredentialEntries().size();
@@ -217,6 +236,11 @@ public class ProviderSessionMetric {
});
ResponseCollective responseCollective = new ResponseCollective(responseCounts, entryCounts);
- mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
+
+ if (!isAuthEntry) {
+ mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
+ } else {
+ // TODO(b/immediately) - Add the auth entry get logic
+ }
}
}
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 4874378a8c21..03ffe23f9886 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -21,10 +21,11 @@ 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;
+import static com.android.server.credentials.MetricUtilities.logApiCalledNoUidFinal;
+import android.annotation.NonNull;
import android.credentials.GetCredentialRequest;
import android.credentials.ui.UserSelectionDialogResult;
-import android.os.IBinder;
import android.util.Slog;
import com.android.server.credentials.ProviderSession;
@@ -48,13 +49,24 @@ public class RequestSessionMetric {
// As emits occur in sequential order, increment this counter and utilize
protected int mSequenceCounter = 0;
- protected final InitialPhaseMetric mInitialPhaseMetric = new InitialPhaseMetric();
+ protected final InitialPhaseMetric mInitialPhaseMetric;
protected final ChosenProviderFinalPhaseMetric
- mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric();
+ mChosenProviderFinalPhaseMetric;
// TODO(b/271135048) - Replace this with a new atom per each browsing emit (V4)
protected List<CandidateBrowsingPhaseMetric> mCandidateBrowsingPhaseMetric = new ArrayList<>();
+ // Specific aggregate candidate provider metric for the provider this session handles
+ @NonNull
+ protected final CandidateAggregateMetric mCandidateAggregateMetric;
+ // Since track two is shared, this allows provider sessions to capture a metric-specific
+ // session token for the flow where the provider is known
+ private final int mSessionIdTrackTwo;
- public RequestSessionMetric() {
+ public RequestSessionMetric(int sessionIdTrackOne, int sessionIdTrackTwo) {
+ mSessionIdTrackTwo = sessionIdTrackTwo;
+ mInitialPhaseMetric = new InitialPhaseMetric(sessionIdTrackOne);
+ mCandidateAggregateMetric = new CandidateAggregateMetric(sessionIdTrackOne);
+ mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric(
+ sessionIdTrackOne, sessionIdTrackTwo);
}
/**
@@ -76,18 +88,25 @@ public class RequestSessionMetric {
}
/**
+ * @return the aggregate candidate phase metrics associated with the request session
+ */
+ public CandidateAggregateMetric getCandidateAggregateMetric() {
+ return mCandidateAggregateMetric;
+ }
+
+ /**
* Upon starting the service, this fills the initial phase metric properly.
*
* @param timestampStarted the timestamp the service begins at
- * @param mRequestId the IBinder used to retrieve a unique id
* @param mCallingUid the calling process's uid
* @param metricCode typically pulled from {@link ApiName}
+ * @param callingAppFlowUniqueInt the unique integer used as the session id for the calling app
+ * known flow
*/
- public void collectInitialPhaseMetricInfo(long timestampStarted, IBinder mRequestId,
+ public void collectInitialPhaseMetricInfo(long timestampStarted,
int mCallingUid, int metricCode) {
try {
mInitialPhaseMetric.setCredentialServiceStartedTimeNanoseconds(timestampStarted);
- mInitialPhaseMetric.setSessionId(mRequestId.hashCode());
mInitialPhaseMetric.setCallerUid(mCallingUid);
mInitialPhaseMetric.setApiName(metricCode);
} catch (Exception e) {
@@ -206,7 +225,6 @@ public class RequestSessionMetric {
CandidatePhaseMetric selectedProviderPhaseMetric) {
try {
CandidateBrowsingPhaseMetric browsingPhaseMetric = new CandidateBrowsingPhaseMetric();
- browsingPhaseMetric.setSessionId(mInitialPhaseMetric.getSessionId());
browsingPhaseMetric.setEntryEnum(
EntryEnum.getMetricCodeFromString(selection.getEntryKey()));
browsingPhaseMetric.setProviderUid(selectedProviderPhaseMetric.getCandidateUid());
@@ -274,7 +292,6 @@ public class RequestSessionMetric {
*/
public void collectChosenMetricViaCandidateTransfer(CandidatePhaseMetric candidatePhaseMetric) {
try {
- mChosenProviderFinalPhaseMetric.setSessionId(candidatePhaseMetric.getSessionId());
mChosenProviderFinalPhaseMetric.setChosenUid(candidatePhaseMetric.getCandidateUid());
mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds(
@@ -332,6 +349,20 @@ public class RequestSessionMetric {
}
/**
+ * Handles aggregate candidate phase metric emits in the RequestSession context, after the
+ * candidate phase completes.
+ *
+ * @param providers a map with known providers and their held metric objects
+ */
+ public void logCandidateAggregateMetrics(Map<String, ProviderSession> providers) {
+ try {
+ mCandidateAggregateMetric.collectAverages(providers);
+ } catch (Exception e) {
+ Slog.i(TAG, "Unexpected error during aggregate candidate logging " + e);
+ }
+ }
+
+ /**
* Handles the final logging for RequestSession context for the final phase.
*
* @param apiStatus the final status of the api being called
@@ -341,9 +372,15 @@ public class RequestSessionMetric {
logApiCalledFinalPhase(mChosenProviderFinalPhaseMetric, mCandidateBrowsingPhaseMetric,
apiStatus,
++mSequenceCounter);
+ logApiCalledNoUidFinal(mChosenProviderFinalPhaseMetric, mCandidateBrowsingPhaseMetric,
+ apiStatus,
+ ++mSequenceCounter);
} catch (Exception e) {
Slog.i(TAG, "Unexpected error during final metric emit: " + e);
}
}
+ public int getSessionIdTrackTwo() {
+ return mSessionIdTrackTwo;
+ }
}