diff options
5 files changed, 94 insertions, 30 deletions
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index f39de43b5076..0271727249b1 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -19,7 +19,6 @@ package com.android.server.credentials; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; -import android.credentials.CredentialOption; import android.credentials.CredentialProviderInfo; import android.credentials.GetCredentialException; import android.credentials.GetCredentialRequest; @@ -36,7 +35,6 @@ import com.android.server.credentials.metrics.ProviderStatusForMetrics; import java.util.ArrayList; import java.util.Set; -import java.util.stream.Collectors; /** * Central session for a single getCredentials request. This class listens to the @@ -56,11 +54,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, super(context, sessionCallback, lock, userId, callingUid, request, callback, RequestInfo.TYPE_GET, callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp); - int numTypes = (request.getCredentialOptions().stream() - .map(CredentialOption::getType).collect( - Collectors.toSet())).size(); // Dedupe type strings - mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes, - /*origin=*/request.getOrigin() != null); + mRequestSessionMetric.collectGetFlowInitialMetricInfo(request); } /** diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index 47b45ac1d53d..c07f06b332fb 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -50,6 +50,8 @@ public class MetricUtilities { public static final int UNIT = 1; // Used for zero count metric emits, such as zero amounts of various types public static final int ZERO = 0; + // The number of characters at the end of the string to use as a key + public static final int DELTA_CUT = 20; /** * This retrieves the uid of any package name, given a context and a component name for the @@ -87,6 +89,18 @@ public class MetricUtilities { } /** + * Given the current design, we can designate how the strings in the backend should appear. + * This helper method lets us cut strings for our class types. + * + * @param classtype the classtype string we want to cut to generate a key + * @param deltaFromEnd the starting point from the end of the string we wish to begin at + * @return the cut up string key we want to use for metric logs + */ + public static String generateMetricKey(String classtype, int deltaFromEnd) { + return classtype.substring(classtype.length() - deltaFromEnd); + } + + /** * A logging utility used primarily for the final phase of the current metric setup. * * @param finalPhaseMetric the coalesced data of the chosen provider @@ -158,7 +172,9 @@ public class MetricUtilities { } /** - * A logging utility used primarily for the candidate phase of the current metric setup. + * 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, + * but NOT the calling app. * * @param providers a map with known providers and their held metric objects * @param emitSequenceId an emitted sequence id for the current session @@ -209,6 +225,7 @@ public class MetricUtilities { candidateActionEntryCountList[index] = metric.getActionEntryCount(); candidateAuthEntryCountList[index] = metric.getAuthenticationEntryCount(); candidateRemoteEntryCountList[index] = metric.getRemoteEntryCount(); + // frameworkExceptionList[index] = metric.getFrameworkException(); index++; } FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED, @@ -297,10 +314,11 @@ public class MetricUtilities { initialPhaseMetric.getCredentialServiceStartedTimeNanoseconds(), /* count_credential_request_classtypes */ initialPhaseMetric.getCountRequestClassType(), - // TODO(b/271135048) - add total count of request options - // TODO(b/271135048) - Uncomment once built past PWG review - - DEFAULT_REPEATED_STR, - DEFAULT_REPEATED_INT_32, + /* request_unique_classtypes */ + initialPhaseMetric.getUniqueRequestStrings(), + /* per_classtype_counts */ + initialPhaseMetric.getUniqueRequestCounts(), + /* origin_specified */ initialPhaseMetric.isOriginSpecified() ); } catch (Exception e) { diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java index 1c3d213c8072..441c87b1569a 100644 --- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java @@ -59,8 +59,7 @@ public class PrepareGetRequestSession extends GetRequestSession { int numTypes = (request.getCredentialOptions().stream() .map(CredentialOption::getType).collect( Collectors.toSet())).size(); // Dedupe type strings - mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes, - /*origin=*/request.getOrigin() != null); + mRequestSessionMetric.collectGetFlowInitialMetricInfo(request); mPrepareGetCredentialCallback = prepareGetCredentialCallback; } 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 0210b14943db..0ecd9cc79e48 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java @@ -16,6 +16,11 @@ package com.android.server.credentials.metrics; +import android.util.Log; + +import java.util.LinkedHashMap; +import java.util.Map; + /** * This handles metrics collected prior to any remote calls to providers. * Some types are redundant across these metric collectors, but that has debug use-cases as @@ -32,7 +37,6 @@ public class InitialPhaseMetric { private int mCallerUid = -1; // The session id to unite multiple atom emits, default to -1 private int mSessionId = -1; - private int mCountRequestClassType = -1; // Raw timestamps in nanoseconds, *the only* one logged as such (i.e. 64 bits) since it is a // reference point. @@ -46,6 +50,9 @@ public class InitialPhaseMetric { // TODO(b/271135048) - Emit once metrics approved private boolean mOriginSpecified = false; + // Stores the deduped request information, particularly {"req":5}. + private Map<String, Integer> mRequestCounts = new LinkedHashMap<>(); + public InitialPhaseMetric() { } @@ -55,8 +62,8 @@ public class InitialPhaseMetric { /* -- Direct Latency Utility -- */ public int getServiceStartToQueryLatencyMicroseconds() { - return (int) ((this.mCredentialServiceStartedTimeNanoseconds - - this.mCredentialServiceBeginQueryTimeNanoseconds) / 1000); + return (int) ((mCredentialServiceStartedTimeNanoseconds + - mCredentialServiceBeginQueryTimeNanoseconds) / 1000); } /* -- Timestamps -- */ @@ -64,7 +71,7 @@ public class InitialPhaseMetric { public void setCredentialServiceStartedTimeNanoseconds( long credentialServiceStartedTimeNanoseconds ) { - this.mCredentialServiceStartedTimeNanoseconds = credentialServiceStartedTimeNanoseconds; + mCredentialServiceStartedTimeNanoseconds = credentialServiceStartedTimeNanoseconds; } public void setCredentialServiceBeginQueryTimeNanoseconds( @@ -112,14 +119,12 @@ public class InitialPhaseMetric { /* ------ Count Request Class Types ------ */ - public void setCountRequestClassType(int countRequestClassType) { - mCountRequestClassType = countRequestClassType; - } - public int getCountRequestClassType() { - return mCountRequestClassType; + return mRequestCounts.size(); } + /* ------ Origin Specified ------ */ + public void setOriginSpecified(boolean originSpecified) { mOriginSpecified = originSpecified; } @@ -127,4 +132,34 @@ public class InitialPhaseMetric { public boolean isOriginSpecified() { return mOriginSpecified; } + + /* ------ Unique Request Counts Map Information ------ */ + + public void setRequestCounts(Map<String, Integer> requestCounts) { + mRequestCounts = requestCounts; + } + + /** + * Reruns the unique, deduped, request classtypes for logging. + * @return a string array for deduped classtypes + */ + public String[] getUniqueRequestStrings() { + if (mRequestCounts.isEmpty()) { + Log.w(TAG, "There are no unique string request types collected"); + } + String[] result = new String[mRequestCounts.keySet().size()]; + mRequestCounts.keySet().toArray(result); + return result; + } + + /** + * Reruns the unique, deduped, request classtype counts for logging. + * @return a string array for deduped classtype counts + */ + public int[] getUniqueRequestCounts() { + if (mRequestCounts.isEmpty()) { + Log.w(TAG, "There are no unique string request type counts collected"); + } + return mRequestCounts.values().stream().mapToInt(Integer::intValue).toArray(); + } } 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 10bf56c853f5..18e04df9416a 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java @@ -16,10 +16,12 @@ package com.android.server.credentials.metrics; +import static com.android.server.credentials.MetricUtilities.DELTA_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 android.annotation.NonNull; +import android.credentials.GetCredentialRequest; import android.credentials.ui.UserSelectionDialogResult; import android.os.IBinder; import android.util.Log; @@ -27,6 +29,7 @@ import android.util.Log; import com.android.server.credentials.ProviderSession; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -48,7 +51,6 @@ public class RequestSessionMetric { protected final ChosenProviderFinalPhaseMetric mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric(); // TODO(b/271135048) - Replace this with a new atom per each browsing emit (V4) - @NonNull protected List<CandidateBrowsingPhaseMetric> mCandidateBrowsingPhaseMetric = new ArrayList<>(); public RequestSessionMetric() { @@ -161,16 +163,32 @@ public class RequestSessionMetric { } } + // Used by get flows to generate the unique request count maps + private Map<String, Integer> getRequestCountMap(GetCredentialRequest request) { + Map<String, Integer> uniqueRequestCounts = new LinkedHashMap<>(); + try { + request.getCredentialOptions().forEach(option -> { + String optionKey = generateMetricKey(option.getType(), DELTA_CUT); + if (!uniqueRequestCounts.containsKey(optionKey)) { + uniqueRequestCounts.put(optionKey, 0); + } + uniqueRequestCounts.put(optionKey, uniqueRequestCounts.get(optionKey) + 1); + }); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during get request metric logging: " + e); + } + return uniqueRequestCounts; + } + /** * Collects initializations for Get flow metrics. * - * @param requestClassTypeCount the number of class types in the request - * @param origin indicates if an origin was passed in or not + * @param request the get credential request containing information to parse for metrics */ - public void collectGetFlowInitialMetricInfo(int requestClassTypeCount, boolean origin) { + public void collectGetFlowInitialMetricInfo(GetCredentialRequest request) { try { - mInitialPhaseMetric.setCountRequestClassType(requestClassTypeCount); - mInitialPhaseMetric.setOriginSpecified(origin); + mInitialPhaseMetric.setOriginSpecified(request.getOrigin() != null); + mInitialPhaseMetric.setRequestCounts(getRequestCountMap(request)); } catch (Exception e) { Log.w(TAG, "Unexpected error during metric logging: " + e); } |