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

Commit d10dc902 authored by Arpan Kaphle's avatar Arpan Kaphle Committed by Android (Google) Code Review
Browse files

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
parents 63ff47ec 35509db0
Loading
Loading
Loading
Loading
+134 −42
Original line number Diff line number Diff line
@@ -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,23 +442,29 @@ public class MetricUtilities {
            int sequenceNum) {
        try {
            if (!LOG_FLAG) {
                return;
            }
            FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_TOTAL_REPORTED,
                    /*session_id*/ candidateAggregateMetric.getSessionIdProvider(),
                    /*sequence_num*/ sequenceNum,
                    /*query_returned*/ candidateAggregateMetric.isQueryReturned(),
                        /*num_providers*/ candidateAggregateMetric.getNumProviders(),
                    /*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*/
                        DEFAULT_REPEATED_STR,
                    candidateAggregateMetric.getAggregateCollectiveQuery()
                            .getUniqueResponseStrings(),
                    /*query_per_classtype_counts*/
                        DEFAULT_REPEATED_INT_32,
                    candidateAggregateMetric.getAggregateCollectiveQuery()
                            .getUniqueResponseCounts(),
                    /*query_unique_entries*/
                        DEFAULT_REPEATED_INT_32,
                    candidateAggregateMetric.getAggregateCollectiveQuery()
                            .getUniqueEntries(),
                    /*query_per_entry_counts*/
                        DEFAULT_REPEATED_INT_32,
                    candidateAggregateMetric.getAggregateCollectiveQuery()
                            .getUniqueEntryCounts(),
                    /*query_total_candidate_failure*/
                    DEFAULT_INT_32,
                    /*query_framework_exception_unique_classtypes*/
@@ -383,13 +472,17 @@ public class MetricUtilities {
                    /*query_per_exception_classtype_counts*/
                    DEFAULT_REPEATED_INT_32,
                    /*auth_response_unique_classtypes*/
                        DEFAULT_REPEATED_STR,
                    candidateAggregateMetric.getAggregateCollectiveAuth()
                            .getUniqueResponseStrings(),
                    /*auth_per_classtype_counts*/
                        DEFAULT_REPEATED_INT_32,
                    candidateAggregateMetric.getAggregateCollectiveAuth()
                            .getUniqueResponseCounts(),
                    /*auth_unique_entries*/
                        DEFAULT_REPEATED_INT_32,
                    candidateAggregateMetric.getAggregateCollectiveAuth()
                            .getUniqueEntries(),
                    /*auth_per_entry_counts*/
                        DEFAULT_REPEATED_INT_32,
                    candidateAggregateMetric.getAggregateCollectiveAuth()
                            .getUniqueEntryCounts(),
                    /*auth_total_candidate_failure*/
                    DEFAULT_INT_32,
                    /*auth_framework_exception_unique_classtypes*/
@@ -397,10 +490,9 @@ public class MetricUtilities {
                    /*auth_per_exception_classtype_counts*/
                    DEFAULT_REPEATED_INT_32,
                    /*num_auth_clicks*/
                        DEFAULT_INT_32,
                    candidateAggregateMetric.getNumAuthEntriesTapped(),
                    /*auth_returned*/ false
            );
            }
        } catch (Exception e) {
            Slog.w(TAG, "Unexpected error during metric logging: " + e);
        }
+2 −0
Original line number Diff line number Diff line
@@ -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.
+11 −0
Original line number Diff line number Diff line
@@ -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) {
+70 −0
Original line number Diff line number Diff line
@@ -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;
    }
}
+63 −5
Original line number Diff line number Diff line
@@ -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,15 +63,48 @@ 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 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 metric = session.getProviderSessionMetric();
            mQueryReturned = mQueryReturned || metric
                    .mCandidatePhasePerProviderMetric.isQueryReturned();
            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() {
        return mNumProviders;
@@ -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;
    }
}
Loading