Merge changes Ib3db0b27,I82c2f747,If4b77e08,I17ac83de into udc-dev
* changes: Auth Entry Metric Exceptions and Status Sets up Emit for Auth Entry Handling sequential auth entries in metrics Extends the CandidateAverageMetric with Auth Entry
This commit is contained in:
@@ -24,6 +24,7 @@ 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.BrowsedAuthenticationMetric;
|
||||
import com.android.server.credentials.metrics.CandidateAggregateMetric;
|
||||
import com.android.server.credentials.metrics.CandidateBrowsingPhaseMetric;
|
||||
import com.android.server.credentials.metrics.CandidatePhaseMetric;
|
||||
@@ -45,6 +46,7 @@ public class MetricUtilities {
|
||||
|
||||
private static final String TAG = "MetricUtilities";
|
||||
public static final String USER_CANCELED_SUBSTRING = "TYPE_USER_CANCELED";
|
||||
public static final int MIN_EMIT_WAIT_TIME_MS = 10;
|
||||
|
||||
public static final int DEFAULT_INT_32 = -1;
|
||||
public static final String DEFAULT_STRING = "";
|
||||
@@ -117,7 +119,8 @@ public class MetricUtilities {
|
||||
}
|
||||
|
||||
/**
|
||||
* A logging utility used primarily for the final phase of the current metric setup.
|
||||
* A logging utility used primarily for the final phase of the current metric setup, focused on
|
||||
* track 2, where the provider uid is known.
|
||||
*
|
||||
* @param finalPhaseMetric the coalesced data of the chosen provider
|
||||
* @param browsingPhaseMetrics the coalesced data of the browsing phase
|
||||
@@ -188,6 +191,86 @@ public class MetricUtilities {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This emits the authentication entry metrics for track 2, where the provider uid is known.
|
||||
*
|
||||
* @param authenticationMetric the authentication metric collection to emit with
|
||||
* @param emitSequenceId an emitted sequence id for the current session
|
||||
*/
|
||||
public static void logApiCalledAuthenticationMetric(
|
||||
BrowsedAuthenticationMetric authenticationMetric,
|
||||
int emitSequenceId) {
|
||||
try {
|
||||
if (!LOG_FLAG) {
|
||||
return;
|
||||
}
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_AUTH_CLICK_REPORTED,
|
||||
/* session_id */ authenticationMetric.getSessionIdProvider(),
|
||||
/* sequence_num */ emitSequenceId,
|
||||
/* chosen_provider_uid */ authenticationMetric.getProviderUid(),
|
||||
/* unique_response_classtypes */
|
||||
authenticationMetric.getAuthEntryCollective().getUniqueResponseStrings(),
|
||||
/* per_classtype_counts */
|
||||
authenticationMetric.getAuthEntryCollective().getUniqueResponseCounts(),
|
||||
/* unique_entries */
|
||||
authenticationMetric.getAuthEntryCollective().getUniqueEntries(),
|
||||
/* auth_per_entry_counts */
|
||||
authenticationMetric.getAuthEntryCollective().getUniqueEntryCounts(),
|
||||
/* framework_exception_unique_classtype */
|
||||
authenticationMetric.getFrameworkException(),
|
||||
/* exception_specified */ authenticationMetric.isHasException(),
|
||||
/* auth_provider_status */
|
||||
authenticationMetric.getProviderStatus(),
|
||||
/* query_returned */
|
||||
authenticationMetric.isQueryReturned()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unexpected error during candidate get metric logging: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A logging utility used primarily for the candidate phase's get responses in the current
|
||||
* metric setup. This helps avoid nested proto-files. This is primarily focused on track 2,
|
||||
* where the provider uid is known. It ensures to run in a separate thread while emitting
|
||||
* the multiple atoms to work with expected emit limits.
|
||||
*
|
||||
* @param providers a map with known providers and their held metric objects
|
||||
* @param emitSequenceId an emitted sequence id for the current session, that matches the
|
||||
* candidate emit value, as these metrics belong with the candidates
|
||||
*/
|
||||
public static void logApiCalledCandidateGetMetric(Map<String, ProviderSession> providers,
|
||||
int emitSequenceId) {
|
||||
try {
|
||||
// TODO(b/274954697) : To queue format in future optimizations (metrics POC support)
|
||||
if (!LOG_FLAG) {
|
||||
return;
|
||||
}
|
||||
var sessions = providers.values();
|
||||
for (var session : sessions) {
|
||||
try {
|
||||
var metric = session.getProviderSessionMetric()
|
||||
.getCandidatePhasePerProviderMetric();
|
||||
FrameworkStatsLog.write(
|
||||
FrameworkStatsLog.CREDENTIAL_MANAGER_GET_REPORTED,
|
||||
/* session_id */ metric.getSessionIdProvider(),
|
||||
/* sequence_num */ emitSequenceId,
|
||||
/* candidate_provider_uid */ metric.getCandidateUid(),
|
||||
/* response_unique_classtypes */
|
||||
metric.getResponseCollective().getUniqueResponseStrings(),
|
||||
/* per_classtype_counts */
|
||||
metric.getResponseCollective().getUniqueResponseCounts()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unexpected exception during get metric logging" + e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unexpected error during candidate get metric logging: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A logging utility used primarily for the candidate phase of the current metric setup. This
|
||||
* will primarily focus on track 2, where the session id is associated with known providers,
|
||||
@@ -359,48 +442,57 @@ public class MetricUtilities {
|
||||
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
|
||||
);
|
||||
return;
|
||||
}
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_TOTAL_REPORTED,
|
||||
/*session_id*/ candidateAggregateMetric.getSessionIdProvider(),
|
||||
/*sequence_num*/ sequenceNum,
|
||||
/*query_returned*/ candidateAggregateMetric.isQueryReturned(),
|
||||
/*num_query_providers*/ candidateAggregateMetric.getNumProviders(),
|
||||
/*min_query_start_timestamp_microseconds*/
|
||||
DEFAULT_INT_32,
|
||||
/*max_query_end_timestamp_microseconds*/
|
||||
DEFAULT_INT_32,
|
||||
/*query_response_unique_classtypes*/
|
||||
candidateAggregateMetric.getAggregateCollectiveQuery()
|
||||
.getUniqueResponseStrings(),
|
||||
/*query_per_classtype_counts*/
|
||||
candidateAggregateMetric.getAggregateCollectiveQuery()
|
||||
.getUniqueResponseCounts(),
|
||||
/*query_unique_entries*/
|
||||
candidateAggregateMetric.getAggregateCollectiveQuery()
|
||||
.getUniqueEntries(),
|
||||
/*query_per_entry_counts*/
|
||||
candidateAggregateMetric.getAggregateCollectiveQuery()
|
||||
.getUniqueEntryCounts(),
|
||||
/*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*/
|
||||
candidateAggregateMetric.getAggregateCollectiveAuth()
|
||||
.getUniqueResponseStrings(),
|
||||
/*auth_per_classtype_counts*/
|
||||
candidateAggregateMetric.getAggregateCollectiveAuth()
|
||||
.getUniqueResponseCounts(),
|
||||
/*auth_unique_entries*/
|
||||
candidateAggregateMetric.getAggregateCollectiveAuth()
|
||||
.getUniqueEntries(),
|
||||
/*auth_per_entry_counts*/
|
||||
candidateAggregateMetric.getAggregateCollectiveAuth()
|
||||
.getUniqueEntryCounts(),
|
||||
/*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*/
|
||||
candidateAggregateMetric.getNumAuthEntriesTapped(),
|
||||
/*auth_returned*/ false
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unexpected error during metric logging: " + e);
|
||||
}
|
||||
|
||||
@@ -269,6 +269,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
|
||||
case AUTHENTICATION_ACTION_ENTRY_KEY:
|
||||
Action authenticationEntry = mProviderResponseDataHandler
|
||||
.getAuthenticationAction(entryKey);
|
||||
mProviderSessionMetric.createAuthenticationBrowsingMetric();
|
||||
if (authenticationEntry == null) {
|
||||
Slog.i(TAG, "Unexpected authenticationEntry key");
|
||||
invokeCallbackOnInternalInvalidState();
|
||||
@@ -423,6 +424,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
|
||||
providerPendingIntentResponse);
|
||||
if (exception != null) {
|
||||
// TODO (b/271135048), for AuthenticationEntry callback selection, set error
|
||||
mProviderSessionMetric.collectAuthenticationExceptionStatus(/*hasException*/true);
|
||||
invokeCallbackWithError(exception.getType(),
|
||||
exception.getMessage());
|
||||
// Additional content received is in the form of an exception which ends the flow.
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.util.Slog;
|
||||
import com.android.internal.R;
|
||||
import com.android.server.credentials.metrics.ApiName;
|
||||
import com.android.server.credentials.metrics.ApiStatus;
|
||||
import com.android.server.credentials.metrics.ProviderSessionMetric;
|
||||
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
|
||||
import com.android.server.credentials.metrics.RequestSessionMetric;
|
||||
|
||||
@@ -199,10 +200,20 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
|
||||
Slog.w(TAG, "providerSession not found in onUiSelection. This is strange.");
|
||||
return;
|
||||
}
|
||||
ProviderSessionMetric providerSessionMetric = providerSession.mProviderSessionMetric;
|
||||
int initialAuthMetricsProvider = providerSessionMetric.getBrowsedAuthenticationMetric()
|
||||
.size();
|
||||
mRequestSessionMetric.collectMetricPerBrowsingSelect(selection,
|
||||
providerSession.mProviderSessionMetric.getCandidatePhasePerProviderMetric());
|
||||
providerSession.onUiEntrySelected(selection.getEntryKey(),
|
||||
selection.getEntrySubkey(), selection.getPendingIntentProviderResponse());
|
||||
int numAuthPerProvider = providerSessionMetric.getBrowsedAuthenticationMetric().size();
|
||||
boolean authMetricLogged = (numAuthPerProvider - initialAuthMetricsProvider) == 1;
|
||||
if (authMetricLogged) {
|
||||
mRequestSessionMetric.logAuthEntry(
|
||||
providerSession.mProviderSessionMetric.getBrowsedAuthenticationMetric()
|
||||
.get(numAuthPerProvider - 1));
|
||||
}
|
||||
}
|
||||
|
||||
protected void finishSession(boolean propagateCancellation) {
|
||||
|
||||
@@ -16,13 +16,34 @@
|
||||
|
||||
package com.android.server.credentials.metrics;
|
||||
|
||||
import com.android.server.credentials.metrics.shared.ResponseCollective;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
private static final String TAG = "BrowsedAuthenticationMetric";
|
||||
// The session id of this provider known flow related metric
|
||||
private final int mSessionIdProvider;
|
||||
|
||||
// The provider associated with the press, defaults to -1
|
||||
private int mProviderUid = -1;
|
||||
|
||||
// The response objects collected for this authentication entry click, default empty
|
||||
private ResponseCollective mAuthEntryCollective = new ResponseCollective(Map.of(), Map.of());
|
||||
|
||||
// Indicates if an exception was thrown by this provider, false by default
|
||||
private boolean mHasException = false;
|
||||
// Indicates the framework only exception belonging to this provider, defaults to empty string
|
||||
private String mFrameworkException = "";
|
||||
// The status of this particular provider
|
||||
private int mProviderStatus = -1;
|
||||
// Indicates if this provider returned from the authentication entry query, default false
|
||||
private boolean mQueryReturned = false;
|
||||
|
||||
// TODO(b/271135048) - Match the atom and provide a clean per provider session metric
|
||||
// encapsulation.
|
||||
|
||||
@@ -33,4 +54,53 @@ public class BrowsedAuthenticationMetric {
|
||||
public int getSessionIdProvider() {
|
||||
return mSessionIdProvider;
|
||||
}
|
||||
|
||||
public void setProviderUid(int providerUid) {
|
||||
mProviderUid = providerUid;
|
||||
}
|
||||
|
||||
public int getProviderUid() {
|
||||
return mProviderUid;
|
||||
}
|
||||
|
||||
public void setAuthEntryCollective(
|
||||
ResponseCollective authEntryCollective) {
|
||||
this.mAuthEntryCollective = authEntryCollective;
|
||||
}
|
||||
|
||||
public ResponseCollective getAuthEntryCollective() {
|
||||
return mAuthEntryCollective;
|
||||
}
|
||||
|
||||
public void setHasException(boolean hasException) {
|
||||
mHasException = hasException;
|
||||
}
|
||||
|
||||
public void setFrameworkException(String frameworkException) {
|
||||
mFrameworkException = frameworkException;
|
||||
}
|
||||
|
||||
public void setProviderStatus(int providerStatus) {
|
||||
mProviderStatus = providerStatus;
|
||||
}
|
||||
|
||||
public void setQueryReturned(boolean queryReturned) {
|
||||
mQueryReturned = queryReturned;
|
||||
}
|
||||
|
||||
public boolean isQueryReturned() {
|
||||
return mQueryReturned;
|
||||
}
|
||||
|
||||
public int getProviderStatus() {
|
||||
return mProviderStatus;
|
||||
}
|
||||
|
||||
public String getFrameworkException() {
|
||||
return mFrameworkException;
|
||||
}
|
||||
|
||||
public boolean isHasException() {
|
||||
return mHasException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package com.android.server.credentials.metrics;
|
||||
|
||||
import com.android.server.credentials.ProviderSession;
|
||||
import com.android.server.credentials.metrics.shared.ResponseCollective;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -29,12 +31,22 @@ 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
|
||||
// Indicates if this provider returned from the candidate query phase,
|
||||
// true if at least one provider returns validly, even if empty, default false
|
||||
private boolean mQueryReturned = false;
|
||||
// Indicates the total number of providers this aggregate captures information for, default 0
|
||||
private int mNumProviders = 0;
|
||||
// Indicates if the authentication entry returned, true if at least one entry returns validly,
|
||||
// even if empty, default false
|
||||
private boolean mAuthReturned = false;
|
||||
// Indicates the total number of authentication entries that were tapped in aggregate, default 0
|
||||
private int mNumAuthEntriesTapped = 0;
|
||||
// The combined aggregate collective across the candidate get/create
|
||||
private ResponseCollective mAggregateCollectiveQuery =
|
||||
new ResponseCollective(Map.of(), Map.of());
|
||||
// The combined aggregate collective across the auth entry info
|
||||
private ResponseCollective mAggregateCollectiveAuth =
|
||||
new ResponseCollective(Map.of(), Map.of());
|
||||
|
||||
public CandidateAggregateMetric(int sessionIdTrackOne) {
|
||||
mSessionIdProvider = sessionIdTrackOne;
|
||||
@@ -51,14 +63,47 @@ public class CandidateAggregateMetric {
|
||||
* @param providers the providers associated with the candidate flow
|
||||
*/
|
||||
public void collectAverages(Map<String, ProviderSession> providers) {
|
||||
// TODO(b/271135048) : Complete this method
|
||||
collectQueryAggregates(providers);
|
||||
collectAuthAggregates(providers);
|
||||
}
|
||||
|
||||
private void collectQueryAggregates(Map<String, ProviderSession> providers) {
|
||||
mNumProviders = providers.size();
|
||||
Map<String, Integer> responseCountQuery = new LinkedHashMap<>();
|
||||
Map<EntryEnum, Integer> entryCountQuery = new LinkedHashMap<>();
|
||||
var providerSessions = providers.values();
|
||||
for (var session : providerSessions) {
|
||||
var metric = session.getProviderSessionMetric();
|
||||
mQueryReturned = mQueryReturned || metric
|
||||
.mCandidatePhasePerProviderMetric.isQueryReturned();
|
||||
var sessionMetric = session.getProviderSessionMetric();
|
||||
var candidateMetric = sessionMetric.getCandidatePhasePerProviderMetric();
|
||||
mQueryReturned = mQueryReturned || candidateMetric.isQueryReturned();
|
||||
ResponseCollective candidateCollective = candidateMetric.getResponseCollective();
|
||||
ResponseCollective.combineTypeCountMaps(responseCountQuery,
|
||||
candidateCollective.getResponseCountsMap());
|
||||
ResponseCollective.combineTypeCountMaps(entryCountQuery,
|
||||
candidateCollective.getEntryCountsMap());
|
||||
}
|
||||
mAggregateCollectiveQuery = new ResponseCollective(responseCountQuery, entryCountQuery);
|
||||
}
|
||||
|
||||
private void collectAuthAggregates(Map<String, ProviderSession> providers) {
|
||||
mNumProviders = providers.size();
|
||||
Map<String, Integer> responseCountAuth = new LinkedHashMap<>();
|
||||
Map<EntryEnum, Integer> entryCountAuth = new LinkedHashMap<>();
|
||||
var providerSessions = providers.values();
|
||||
for (var session : providerSessions) {
|
||||
var sessionMetric = session.getProviderSessionMetric();
|
||||
var authMetrics = sessionMetric.getBrowsedAuthenticationMetric();
|
||||
mNumAuthEntriesTapped += authMetrics.size();
|
||||
for (var authMetric : authMetrics) {
|
||||
mAuthReturned = mAuthReturned || authMetric.isQueryReturned();
|
||||
ResponseCollective authCollective = authMetric.getAuthEntryCollective();
|
||||
ResponseCollective.combineTypeCountMaps(responseCountAuth,
|
||||
authCollective.getResponseCountsMap());
|
||||
ResponseCollective.combineTypeCountMaps(entryCountAuth,
|
||||
authCollective.getEntryCountsMap());
|
||||
}
|
||||
}
|
||||
mAggregateCollectiveAuth = new ResponseCollective(responseCountAuth, entryCountAuth);
|
||||
}
|
||||
|
||||
public int getNumProviders() {
|
||||
@@ -69,7 +114,20 @@ public class CandidateAggregateMetric {
|
||||
return mQueryReturned;
|
||||
}
|
||||
|
||||
|
||||
public int getNumAuthEntriesTapped() {
|
||||
return mNumAuthEntriesTapped;
|
||||
}
|
||||
|
||||
public ResponseCollective getAggregateCollectiveQuery() {
|
||||
return mAggregateCollectiveQuery;
|
||||
}
|
||||
|
||||
public ResponseCollective getAggregateCollectiveAuth() {
|
||||
return mAggregateCollectiveAuth;
|
||||
}
|
||||
|
||||
public boolean isAuthReturned() {
|
||||
return mAuthReturned;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.util.Slog;
|
||||
import com.android.server.credentials.MetricUtilities;
|
||||
import com.android.server.credentials.metrics.shared.ResponseCollective;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -47,13 +48,17 @@ public class ProviderSessionMetric {
|
||||
protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric;
|
||||
|
||||
// IFF there was an authentication entry clicked, this stores all required information for
|
||||
// that event. This is for the 'get' flow.
|
||||
// that event. This is for the 'get' flow. Notice these flows may be repetitive.
|
||||
// Thus each provider stores a list of authentication metrics. The time between emits
|
||||
// of these metrics should exceed 10 ms (given human reaction time is ~ 100's of ms), so emits
|
||||
// will never collide. However, for aggregation, this will store information accordingly.
|
||||
@NonNull
|
||||
protected final BrowsedAuthenticationMetric mBrowsedAuthenticationMetric;
|
||||
protected final List<BrowsedAuthenticationMetric> mBrowsedAuthenticationMetric =
|
||||
new ArrayList<>();
|
||||
|
||||
public ProviderSessionMetric(int sessionIdTrackTwo) {
|
||||
mCandidatePhasePerProviderMetric = new CandidatePhaseMetric(sessionIdTrackTwo);
|
||||
mBrowsedAuthenticationMetric = new BrowsedAuthenticationMetric(sessionIdTrackTwo);
|
||||
mBrowsedAuthenticationMetric.add(new BrowsedAuthenticationMetric(sessionIdTrackTwo));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,6 +68,12 @@ public class ProviderSessionMetric {
|
||||
return mCandidatePhasePerProviderMetric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication clicked metric information.
|
||||
*/
|
||||
public List<BrowsedAuthenticationMetric> getBrowsedAuthenticationMetric() {
|
||||
return mBrowsedAuthenticationMetric;
|
||||
}
|
||||
|
||||
/**
|
||||
* This collects for ProviderSessions, with respect to the candidate providers, whether
|
||||
@@ -71,7 +82,30 @@ public class ProviderSessionMetric {
|
||||
* @param hasException indicates if the candidate provider associated with an exception
|
||||
*/
|
||||
public void collectCandidateExceptionStatus(boolean hasException) {
|
||||
mCandidatePhasePerProviderMetric.setHasException(hasException);
|
||||
try {
|
||||
mCandidatePhasePerProviderMetric.setHasException(hasException);
|
||||
} catch (Exception e) {
|
||||
Slog.i(TAG, "Error while setting candidate metric exception " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This collects for ProviderSessions, with respect to the authentication entry provider,
|
||||
* if an exception occurred in the authentication entry click. It's expected that these
|
||||
* collections always occur after at least 1 authentication metric has been collected
|
||||
* for the provider associated with this metric encapsulation.
|
||||
*
|
||||
* @param hasException indicates if the candidate provider from an authentication entry
|
||||
* associated with an exception
|
||||
*/
|
||||
public void collectAuthenticationExceptionStatus(boolean hasException) {
|
||||
try {
|
||||
var mostRecentAuthenticationMetric = mBrowsedAuthenticationMetric
|
||||
.get(mBrowsedAuthenticationMetric.size() - 1);
|
||||
mostRecentAuthenticationMetric.setHasException(hasException);
|
||||
} catch (Exception e) {
|
||||
Slog.i(TAG, "Error while setting authentication metric exception " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,6 +125,21 @@ public class ProviderSessionMetric {
|
||||
// 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.
|
||||
var mostRecentAuthenticationMetric = mBrowsedAuthenticationMetric
|
||||
.get(mBrowsedAuthenticationMetric.size() - 1);
|
||||
mostRecentAuthenticationMetric.setProviderUid(providerSessionUid);
|
||||
// TODO(immediately) - add timestamps (no longer needed!!) but also update below values!
|
||||
if (isFailureStatus) {
|
||||
mostRecentAuthenticationMetric.setQueryReturned(false);
|
||||
mostRecentAuthenticationMetric.setProviderStatus(
|
||||
ProviderStatusForMetrics.QUERY_FAILURE
|
||||
.getMetricCode());
|
||||
} else if (isCompletionStatus) {
|
||||
mostRecentAuthenticationMetric.setQueryReturned(true);
|
||||
mostRecentAuthenticationMetric.setProviderStatus(
|
||||
ProviderStatusForMetrics.QUERY_SUCCESS
|
||||
.getMetricCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,6 +246,17 @@ public class ProviderSessionMetric {
|
||||
mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets up an authentication metric collector to the flow. This must be called before
|
||||
* any logical edits are done in a new authentication entry metric collection.
|
||||
*/
|
||||
public void createAuthenticationBrowsingMetric() {
|
||||
BrowsedAuthenticationMetric browsedAuthenticationMetric =
|
||||
new BrowsedAuthenticationMetric(mCandidatePhasePerProviderMetric
|
||||
.getSessionIdProvider());
|
||||
mBrowsedAuthenticationMetric.add(browsedAuthenticationMetric);
|
||||
}
|
||||
|
||||
private void beginCreateCredentialResponseCollectionCandidateEntryMetrics(
|
||||
BeginCreateCredentialResponse response) {
|
||||
Map<EntryEnum, Integer> entryCounts = new LinkedHashMap<>();
|
||||
@@ -240,7 +300,10 @@ public class ProviderSessionMetric {
|
||||
if (!isAuthEntry) {
|
||||
mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
|
||||
} else {
|
||||
// TODO(b/immediately) - Add the auth entry get logic
|
||||
// The most recent auth entry must be created already
|
||||
var browsedAuthenticationMetric =
|
||||
mBrowsedAuthenticationMetric.get(mBrowsedAuthenticationMetric.size() - 1);
|
||||
browsedAuthenticationMetric.setAuthEntryCollective(responseCollective);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package com.android.server.credentials.metrics;
|
||||
|
||||
import static com.android.server.credentials.MetricUtilities.DEFAULT_INT_32;
|
||||
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.logApiCalledAuthenticationMetric;
|
||||
import static com.android.server.credentials.MetricUtilities.logApiCalledCandidateGetMetric;
|
||||
import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase;
|
||||
import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPhase;
|
||||
import static com.android.server.credentials.MetricUtilities.logApiCalledNoUidFinal;
|
||||
@@ -52,7 +55,6 @@ public class RequestSessionMetric {
|
||||
protected final InitialPhaseMetric mInitialPhaseMetric;
|
||||
protected final 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
|
||||
@@ -100,8 +102,6 @@ public class RequestSessionMetric {
|
||||
* @param timestampStarted the timestamp the service begins at
|
||||
* @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,
|
||||
int mCallingUid, int metricCode) {
|
||||
@@ -214,9 +214,8 @@ public class RequestSessionMetric {
|
||||
|
||||
/**
|
||||
* During browsing, where multiple entries can be selected, this collects the browsing phase
|
||||
* metric information.
|
||||
* TODO(b/271135048) - modify asap to account for a new metric emit per browse response to
|
||||
* framework.
|
||||
* metric information. This is emitted together with the final phase, and the recursive path
|
||||
* with authentication entries, which may occur in rare circumstances, are captured.
|
||||
*
|
||||
* @param selection contains the selected entry key type
|
||||
* @param selectedProviderPhaseMetric contains the utility information of the selected provider
|
||||
@@ -343,6 +342,7 @@ public class RequestSessionMetric {
|
||||
public void logCandidatePhaseMetrics(Map<String, ProviderSession> providers) {
|
||||
try {
|
||||
logApiCalledCandidatePhase(providers, ++mSequenceCounter, mInitialPhaseMetric);
|
||||
logApiCalledCandidateGetMetric(providers, mSequenceCounter);
|
||||
} catch (Exception e) {
|
||||
Slog.i(TAG, "Unexpected error during candidate metric emit: " + e);
|
||||
}
|
||||
@@ -362,6 +362,28 @@ public class RequestSessionMetric {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This logs the authentication entry when browsed. Combined with the known browsed clicks
|
||||
* in the {@link ChosenProviderFinalPhaseMetric}, this fully captures the authentication entry
|
||||
* logic for multiple loops. An auth entry may have default or missing data, but if a provider
|
||||
* was never assigned to an auth entry, this indicates an auth entry was never clicked.
|
||||
* This case is handled in this emit.
|
||||
*
|
||||
* @param browsedAuthenticationMetric the authentication metric information to emit
|
||||
*/
|
||||
public void logAuthEntry(BrowsedAuthenticationMetric browsedAuthenticationMetric) {
|
||||
try {
|
||||
if (browsedAuthenticationMetric.getProviderUid() == DEFAULT_INT_32) {
|
||||
Slog.v(TAG, "An authentication entry was not clicked");
|
||||
return;
|
||||
}
|
||||
logApiCalledAuthenticationMetric(browsedAuthenticationMetric, ++mSequenceCounter);
|
||||
} catch (Exception e) {
|
||||
Slog.i(TAG, "Unexpected error during metric logging: " + e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the final logging for RequestSession context for the final phase.
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
||||
|
||||
import com.android.server.credentials.metrics.EntryEnum;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -69,6 +70,24 @@ public class ResponseCollective {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of the entry counts, safe under the immutability of the
|
||||
* class the original map is held within.
|
||||
* @return an unmodifiable map of the entry : counts
|
||||
*/
|
||||
public Map<EntryEnum, Integer> getEntryCountsMap() {
|
||||
return Collections.unmodifiableMap(mEntryCounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of the response counts, safe under the immutability of the
|
||||
* class the original map is held within.
|
||||
* @return an unmodifiable map of the response : counts
|
||||
*/
|
||||
public Map<String, Integer> getResponseCountsMap() {
|
||||
return Collections.unmodifiableMap(mResponseCounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique, deduped, response classtype counts for logging associated with this
|
||||
* provider.
|
||||
@@ -112,4 +131,44 @@ public class ResponseCollective {
|
||||
public int getNumEntriesTotal() {
|
||||
return mEntryCounts.values().stream().mapToInt(Integer::intValue).sum();
|
||||
}
|
||||
|
||||
/**
|
||||
* This combines the current collective with another collective, only if that other
|
||||
* collective is indeed a differing one in memory.
|
||||
* @param other the other response collective to combine with
|
||||
* @return a combined {@link ResponseCollective} object
|
||||
*/
|
||||
public ResponseCollective combineCollectives(ResponseCollective other) {
|
||||
if (this == other) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Map<String, Integer> responseCounts = new LinkedHashMap<>(other.mResponseCounts);
|
||||
for (String response : mResponseCounts.keySet()) {
|
||||
responseCounts.merge(response, mResponseCounts.get(response), Integer::sum);
|
||||
}
|
||||
|
||||
Map<EntryEnum, Integer> entryCounts = new LinkedHashMap<>(other.mEntryCounts);
|
||||
for (EntryEnum entry : mEntryCounts.keySet()) {
|
||||
entryCounts.merge(entry, mEntryCounts.get(entry), Integer::sum);
|
||||
}
|
||||
|
||||
return new ResponseCollective(responseCounts, entryCounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two maps of type : counts, this combines the second into the first, to get an aggregate
|
||||
* deduped type:count output.
|
||||
* @param first the first map of some type to counts used as the base
|
||||
* @param second the second map of some type to counts that mixies with the first
|
||||
* @param <T> The type of the object we are mix-deduping - i.e. responses or entries.
|
||||
* @return the first map updated with the second map's information for type:counts
|
||||
*/
|
||||
public static <T> Map<T, Integer> combineTypeCountMaps(Map<T, Integer> first,
|
||||
Map<T, Integer> second) {
|
||||
for (T response : second.keySet()) {
|
||||
first.merge(response, first.getOrDefault(response, 0), Integer::sum);
|
||||
}
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user