Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc02288f authored by Arpan Kaphle's avatar Arpan Kaphle
Browse files

Collecting Request:Count metrics

This sets up the collection of the request:count metrics, with unique,
unknown request strings, cut off at a certain point (20 characters to
the end). This is in line with our designed plans, but the exact cut off
point may be discussed. The idea is that the server side context is all
that's needed for queries.

Bug: 271135048
Test: Build + E2E Test in progress (won't submit till that is done)
Change-Id: I5420f6dd09f5b52f71926ad20d89d82f9b369b24
parent 497d09ac
Loading
Loading
Loading
Loading
+1 −7
Original line number Diff line number Diff line
@@ -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);
    }

    /**
+23 −5
Original line number Diff line number Diff line
@@ -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
@@ -86,6 +88,18 @@ public class MetricUtilities {
        return (int) ((t2 - t1) / 1000);
    }

    /**
     * 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.
     *
@@ -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) {
+1 −2
Original line number Diff line number Diff line
@@ -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;
    }

+44 −9
Original line number Diff line number Diff line
@@ -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();
    }
}
+25 −7
Original line number Diff line number Diff line
@@ -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);
        }