Merge changes I52efc7fd,I531c1be0,Ib3870fb1,I94e95ead,I72140e75 into udc-dev

* changes:
  Emit Simple Metrics for Set/GetCredProvider APIs
  Primary Info in Candidate Metric
  Adding isPrimary to Final Phase Metrics
  Setting up the emit of the aggregate phase
  Completely emitting aggr candidate+auth metrics
This commit is contained in:
Arpan Kaphle
2023-05-11 04:53:56 +00:00
committed by Android (Google) Code Review
14 changed files with 263 additions and 61 deletions

View File

@@ -30,8 +30,6 @@ import android.os.RemoteException;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.util.Slog; import android.util.Slog;
import com.android.server.credentials.metrics.ProviderSessionMetric;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Set; import java.util.Set;
@@ -95,12 +93,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
public void onFinalResponseReceived( public void onFinalResponseReceived(
ComponentName componentName, ComponentName componentName,
Void response) { Void response) {
if (mProviders.get(componentName.flattenToString()) != null) { mRequestSessionMetric.updateMetricsOnResponseReceived(mProviders, componentName,
ProviderSessionMetric providerSessionMetric = isPrimaryProviderViaProviderInfo(componentName));
mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
.getCandidatePhasePerProviderMetric());
}
respondToClientWithResponseAndFinish(null); respondToClientWithResponseAndFinish(null);
} }

View File

@@ -35,7 +35,6 @@ import android.service.credentials.CallingAppInfo;
import android.service.credentials.PermissionUtils; import android.service.credentials.PermissionUtils;
import android.util.Slog; import android.util.Slog;
import com.android.server.credentials.metrics.ProviderSessionMetric;
import com.android.server.credentials.metrics.ProviderStatusForMetrics; import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import java.util.ArrayList; import java.util.ArrayList;
@@ -132,12 +131,8 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Nullable CreateCredentialResponse response) { @Nullable CreateCredentialResponse response) {
Slog.i(TAG, "Final credential received from: " + componentName.flattenToString()); Slog.i(TAG, "Final credential received from: " + componentName.flattenToString());
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime()); mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime());
if (mProviders.get(componentName.flattenToString()) != null) { mRequestSessionMetric.updateMetricsOnResponseReceived(mProviders, componentName,
ProviderSessionMetric providerSessionMetric = isPrimaryProviderViaProviderInfo(componentName));
mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
.getCandidatePhasePerProviderMetric());
}
if (response != null) { if (response != null) {
mRequestSessionMetric.collectChosenProviderStatus( mRequestSessionMetric.collectChosenProviderStatus(
ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode()); ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode());

View File

@@ -706,11 +706,18 @@ public final class CredentialManagerService
public void setEnabledProviders( public void setEnabledProviders(
List<String> primaryProviders, List<String> providers, int userId, List<String> primaryProviders, List<String> providers, int userId,
ISetEnabledProvidersCallback callback) { ISetEnabledProvidersCallback callback) {
final int callingUid = Binder.getCallingUid();
if (!hasWriteSecureSettingsPermission()) { if (!hasWriteSecureSettingsPermission()) {
try { try {
MetricUtilities.logApiCalledSimpleV2(
ApiName.SET_ENABLED_PROVIDERS,
ApiStatus.FAILURE, callingUid);
callback.onError( callback.onError(
PERMISSION_DENIED_ERROR, PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR); PERMISSION_DENIED_ERROR, PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR);
} catch (RemoteException e) { } catch (RemoteException e) {
MetricUtilities.logApiCalledSimpleV2(
ApiName.SET_ENABLED_PROVIDERS,
ApiStatus.FAILURE, callingUid);
Slog.e(TAG, "Issue with invoking response: ", e); Slog.e(TAG, "Issue with invoking response: ", e);
} }
return; return;
@@ -744,10 +751,16 @@ public final class CredentialManagerService
if (!writeEnabledStatus || !writePrimaryStatus) { if (!writeEnabledStatus || !writePrimaryStatus) {
Slog.e(TAG, "Failed to store setting containing enabled or primary providers"); Slog.e(TAG, "Failed to store setting containing enabled or primary providers");
try { try {
MetricUtilities.logApiCalledSimpleV2(
ApiName.SET_ENABLED_PROVIDERS,
ApiStatus.FAILURE, callingUid);
callback.onError( callback.onError(
"failed_setting_store", "failed_setting_store",
"Failed to store setting containing enabled or primary providers"); "Failed to store setting containing enabled or primary providers");
} catch (RemoteException e) { } catch (RemoteException e) {
MetricUtilities.logApiCalledSimpleV2(
ApiName.SET_ENABLED_PROVIDERS,
ApiStatus.FAILURE, callingUid);
Slog.e(TAG, "Issue with invoking error response: ", e); Slog.e(TAG, "Issue with invoking error response: ", e);
return; return;
} }
@@ -755,8 +768,14 @@ public final class CredentialManagerService
// Call the callback. // Call the callback.
try { try {
MetricUtilities.logApiCalledSimpleV2(
ApiName.SET_ENABLED_PROVIDERS,
ApiStatus.SUCCESS, callingUid);
callback.onResponse(); callback.onResponse();
} catch (RemoteException e) { } catch (RemoteException e) {
MetricUtilities.logApiCalledSimpleV2(
ApiName.SET_ENABLED_PROVIDERS,
ApiStatus.FAILURE, callingUid);
Slog.e(TAG, "Issue with invoking response: ", e); Slog.e(TAG, "Issue with invoking response: ", e);
// TODO: Propagate failure // TODO: Propagate failure
} }
@@ -805,10 +824,15 @@ public final class CredentialManagerService
public List<CredentialProviderInfo> getCredentialProviderServices( public List<CredentialProviderInfo> getCredentialProviderServices(
int userId, int providerFilter) { int userId, int providerFilter) {
verifyGetProvidersPermission(); verifyGetProvidersPermission();
final int callingUid = Binder.getCallingUid();
return CredentialProviderInfoFactory.getCredentialProviderServices( MetricUtilities.logApiCalledSimpleV2(
ApiName.GET_CREDENTIAL_PROVIDER_SERVICES,
ApiStatus.SUCCESS, callingUid);
return CredentialProviderInfoFactory
.getCredentialProviderServices(
mContext, userId, providerFilter, getEnabledProvidersForUser(userId), mContext, userId, providerFilter, getEnabledProvidersForUser(userId),
getPrimaryProvidersForUserId(mContext, userId)); getPrimaryProvidersForUserId(mContext, userId));
} }
@Override @Override

View File

@@ -34,7 +34,6 @@ import android.service.credentials.CallingAppInfo;
import android.service.credentials.PermissionUtils; import android.service.credentials.PermissionUtils;
import android.util.Slog; import android.util.Slog;
import com.android.server.credentials.metrics.ProviderSessionMetric;
import com.android.server.credentials.metrics.ProviderStatusForMetrics; import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import java.util.ArrayList; import java.util.ArrayList;
@@ -134,13 +133,8 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
public void onFinalResponseReceived(ComponentName componentName, public void onFinalResponseReceived(ComponentName componentName,
@Nullable GetCredentialResponse response) { @Nullable GetCredentialResponse response) {
Slog.i(TAG, "onFinalResponseReceived from: " + componentName.flattenToString()); Slog.i(TAG, "onFinalResponseReceived from: " + componentName.flattenToString());
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime()); mRequestSessionMetric.updateMetricsOnResponseReceived(mProviders, componentName,
if (mProviders.get(componentName.flattenToString()) != null) { isPrimaryProviderViaProviderInfo(componentName));
ProviderSessionMetric providerSessionMetric =
mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
.getCandidatePhasePerProviderMetric());
}
if (response != null) { if (response != null) {
mRequestSessionMetric.collectChosenProviderStatus( mRequestSessionMetric.collectChosenProviderStatus(
ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode()); ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode());

View File

@@ -103,6 +103,10 @@ public class MetricUtilities {
if (t2 - t1 > Integer.MAX_VALUE) { if (t2 - t1 > Integer.MAX_VALUE) {
throw new ArithmeticException("Input timestamps are too far apart and unsupported"); throw new ArithmeticException("Input timestamps are too far apart and unsupported");
} }
if (t2 < t1) {
Slog.i(TAG, "The timestamps aren't in expected order, falling back to default int");
return DEFAULT_INT_32;
}
return (int) ((t2 - t1) / 1000); return (int) ((t2 - t1) / 1000);
} }
@@ -184,7 +188,7 @@ public class MetricUtilities {
finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(), finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
/* framework_exception_unique_classtype */ /* framework_exception_unique_classtype */
finalPhaseMetric.getFrameworkException(), finalPhaseMetric.getFrameworkException(),
/* primary_indicated */ false /* primary_indicated */ finalPhaseMetric.isPrimary()
); );
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected error during final provider uid emit: " + e); Slog.w(TAG, "Unexpected error during final provider uid emit: " + e);
@@ -222,7 +226,7 @@ public class MetricUtilities {
/* auth_provider_status */ /* auth_provider_status */
authenticationMetric.getProviderStatus(), authenticationMetric.getProviderStatus(),
/* query_returned */ /* query_returned */
authenticationMetric.isQueryReturned() authenticationMetric.isAuthReturned()
); );
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected error during candidate get metric logging: " + e); Slog.w(TAG, "Unexpected error during candidate get metric logging: " + e);
@@ -303,6 +307,7 @@ public class MetricUtilities {
int[] candidateAuthEntryCountList = new int[providerSize]; int[] candidateAuthEntryCountList = new int[providerSize];
int[] candidateRemoteEntryCountList = new int[providerSize]; int[] candidateRemoteEntryCountList = new int[providerSize];
String[] frameworkExceptionList = new String[providerSize]; String[] frameworkExceptionList = new String[providerSize];
boolean[] candidatePrimaryProviderList = new boolean[providerSize];
int index = 0; int index = 0;
for (var session : providerSessions) { for (var session : providerSessions) {
CandidatePhaseMetric metric = session.mProviderSessionMetric CandidatePhaseMetric metric = session.mProviderSessionMetric
@@ -335,6 +340,7 @@ public class MetricUtilities {
candidateRemoteEntryCountList[index] = metric.getResponseCollective() candidateRemoteEntryCountList[index] = metric.getResponseCollective()
.getCountForEntry(EntryEnum.REMOTE_ENTRY); .getCountForEntry(EntryEnum.REMOTE_ENTRY);
frameworkExceptionList[index] = metric.getFrameworkException(); frameworkExceptionList[index] = metric.getFrameworkException();
candidatePrimaryProviderList[index] = metric.isPrimary();
index++; index++;
} }
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED, FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED,
@@ -368,7 +374,7 @@ public class MetricUtilities {
/* api_name */ /* api_name */
initialPhaseMetric.getApiName(), initialPhaseMetric.getApiName(),
/* primary_candidates_indicated */ /* primary_candidates_indicated */
DEFAULT_REPEATED_BOOL candidatePrimaryProviderList
); );
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e); Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e);
@@ -450,9 +456,13 @@ public class MetricUtilities {
/*query_returned*/ candidateAggregateMetric.isQueryReturned(), /*query_returned*/ candidateAggregateMetric.isQueryReturned(),
/*num_query_providers*/ candidateAggregateMetric.getNumProviders(), /*num_query_providers*/ candidateAggregateMetric.getNumProviders(),
/*min_query_start_timestamp_microseconds*/ /*min_query_start_timestamp_microseconds*/
DEFAULT_INT_32, getMetricTimestampDifferenceMicroseconds(
candidateAggregateMetric.getMinProviderTimestampNanoseconds(),
candidateAggregateMetric.getServiceBeganTimeNanoseconds()),
/*max_query_end_timestamp_microseconds*/ /*max_query_end_timestamp_microseconds*/
DEFAULT_INT_32, getMetricTimestampDifferenceMicroseconds(
candidateAggregateMetric.getMaxProviderTimestampNanoseconds(),
candidateAggregateMetric.getServiceBeganTimeNanoseconds()),
/*query_response_unique_classtypes*/ /*query_response_unique_classtypes*/
candidateAggregateMetric.getAggregateCollectiveQuery() candidateAggregateMetric.getAggregateCollectiveQuery()
.getUniqueResponseStrings(), .getUniqueResponseStrings(),
@@ -466,11 +476,11 @@ public class MetricUtilities {
candidateAggregateMetric.getAggregateCollectiveQuery() candidateAggregateMetric.getAggregateCollectiveQuery()
.getUniqueEntryCounts(), .getUniqueEntryCounts(),
/*query_total_candidate_failure*/ /*query_total_candidate_failure*/
DEFAULT_INT_32, candidateAggregateMetric.getTotalQueryFailures(),
/*query_framework_exception_unique_classtypes*/ /*query_framework_exception_unique_classtypes*/
DEFAULT_REPEATED_STR, candidateAggregateMetric.getUniqueExceptionStringsQuery(),
/*query_per_exception_classtype_counts*/ /*query_per_exception_classtype_counts*/
DEFAULT_REPEATED_INT_32, candidateAggregateMetric.getUniqueExceptionCountsQuery(),
/*auth_response_unique_classtypes*/ /*auth_response_unique_classtypes*/
candidateAggregateMetric.getAggregateCollectiveAuth() candidateAggregateMetric.getAggregateCollectiveAuth()
.getUniqueResponseStrings(), .getUniqueResponseStrings(),
@@ -484,14 +494,15 @@ public class MetricUtilities {
candidateAggregateMetric.getAggregateCollectiveAuth() candidateAggregateMetric.getAggregateCollectiveAuth()
.getUniqueEntryCounts(), .getUniqueEntryCounts(),
/*auth_total_candidate_failure*/ /*auth_total_candidate_failure*/
DEFAULT_INT_32, candidateAggregateMetric.getTotalAuthFailures(),
/*auth_framework_exception_unique_classtypes*/ /*auth_framework_exception_unique_classtypes*/
DEFAULT_REPEATED_STR, candidateAggregateMetric.getUniqueExceptionStringsAuth(),
/*auth_per_exception_classtype_counts*/ /*auth_per_exception_classtype_counts*/
DEFAULT_REPEATED_INT_32, candidateAggregateMetric.getUniqueExceptionCountsAuth(),
/*num_auth_clicks*/ /*num_auth_clicks*/
candidateAggregateMetric.getNumAuthEntriesTapped(), candidateAggregateMetric.getNumAuthEntriesTapped(),
/*auth_returned*/ false /*auth_returned*/
candidateAggregateMetric.isAuthReturned()
); );
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected error during metric logging: " + e); Slog.w(TAG, "Unexpected error during metric logging: " + e);
@@ -556,7 +567,7 @@ public class MetricUtilities {
/* clicked_entries */ browsedClickedEntries, /* clicked_entries */ browsedClickedEntries,
/* provider_of_clicked_entry */ browsedProviderUid, /* provider_of_clicked_entry */ browsedProviderUid,
/* api_status */ apiStatus, /* api_status */ apiStatus,
/* primary_indicated */ false /* primary_indicated */ finalPhaseMetric.isPrimary()
); );
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected error during metric logging: " + e); Slog.w(TAG, "Unexpected error during metric logging: " + e);

View File

@@ -214,9 +214,11 @@ public abstract class ProviderSession<T, R>
protected void updateStatusAndInvokeCallback(@NonNull Status status, protected void updateStatusAndInvokeCallback(@NonNull Status status,
CredentialsSource source) { CredentialsSource source) {
setStatus(status); setStatus(status);
boolean isPrimary = mProviderInfo != null && mProviderInfo.isPrimary();
mProviderSessionMetric.collectCandidateMetricUpdate(isTerminatingStatus(status), mProviderSessionMetric.collectCandidateMetricUpdate(isTerminatingStatus(status),
isCompletionStatus(status), mProviderSessionUid, isCompletionStatus(status), mProviderSessionUid,
source == CredentialsSource.AUTH_ENTRY); /*isAuthEntry*/source == CredentialsSource.AUTH_ENTRY,
/*isPrimary*/isPrimary);
mCallbacks.onProviderStatusChanged(status, mComponentName, source); mCallbacks.onProviderStatusChanged(status, mComponentName, source);
} }
/** Common method that transfers metrics from the init phase to candidates */ /** Common method that transfers metrics from the init phase to candidates */

View File

@@ -304,6 +304,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
* @param response the response associated with the API call that just completed * @param response the response associated with the API call that just completed
*/ */
protected void respondToClientWithResponseAndFinish(V response) { protected void respondToClientWithResponseAndFinish(V response) {
mRequestSessionMetric.logCandidateAggregateMetrics(mProviders);
mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(/*has_exception=*/ false, mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(/*has_exception=*/ false,
ProviderStatusForMetrics.FINAL_SUCCESS); ProviderStatusForMetrics.FINAL_SUCCESS);
if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) {
@@ -337,6 +338,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
* @param errorMsg the error message given back in the flow * @param errorMsg the error message given back in the flow
*/ */
protected void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { protected void respondToClientWithErrorAndFinish(String errorType, String errorMsg) {
mRequestSessionMetric.logCandidateAggregateMetrics(mProviders);
mRequestSessionMetric.collectFinalPhaseProviderMetricStatus( mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
/*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE); /*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE);
if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) {
@@ -359,4 +361,16 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
mRequestSessionMetric.logFailureOrUserCancel(isUserCanceled); mRequestSessionMetric.logFailureOrUserCancel(isUserCanceled);
finishSession(/*propagateCancellation=*/false); finishSession(/*propagateCancellation=*/false);
} }
/**
* Reveals if a certain provider is primary after ensuring it exists at all in the designated
* provider info.
*
* @param componentName used to identify the provider we want to check primary status for
*/
protected boolean isPrimaryProviderViaProviderInfo(ComponentName componentName) {
var chosenProviderSession = mProviders.get(componentName.flattenToString());
return chosenProviderSession != null && chosenProviderSession.mProviderInfo != null
&& chosenProviderSession.mProviderInfo.isPrimary();
}
} }

View File

@@ -24,8 +24,11 @@ import static android.credentials.ui.RequestInfo.TYPE_UNDEFINED;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CLEAR_CREDENTIAL; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CREATE_CREDENTIAL; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CREATE_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL_PROVIDER_SERVICES;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL_VIA_REGISTRY; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL_VIA_REGISTRY;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_REGISTER_CREDENTIAL_DESCRIPTION;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_SET_ENABLED_PROVIDERS;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN;
import android.credentials.ui.RequestInfo; import android.credentials.ui.RequestInfo;
@@ -45,6 +48,20 @@ CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL_VIA
CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CLEAR_CREDENTIAL), CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CLEAR_CREDENTIAL),
IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE( IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE(
CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE
),
SET_ENABLED_PROVIDERS(
CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_SET_ENABLED_PROVIDERS),
GET_CREDENTIAL_PROVIDER_SERVICES(
CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL_PROVIDER_SERVICES),
REGISTER_CREDENTIAL_DESCRIPTION(
CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_REGISTER_CREDENTIAL_DESCRIPTION
),
UNREGISTER_CREDENTIAL_DESCRIPTION(
CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_REGISTER_CREDENTIAL_DESCRIPTION
); );
private static final String TAG = "ApiName"; private static final String TAG = "ApiName";

View File

@@ -25,10 +25,9 @@ import java.util.Map;
* Contains information about what was collected from the authentication entry output. * Contains information about what was collected from the authentication entry output.
*/ */
public class BrowsedAuthenticationMetric { public class BrowsedAuthenticationMetric {
private static final String TAG = "BrowsedAuthenticationMetric"; private static final String TAG = "AuthenticationMetric";
// The session id of this provider known flow related metric // The session id of this provider known flow related metric
private final int mSessionIdProvider; private final int mSessionIdProvider;
// The provider associated with the press, defaults to -1 // The provider associated with the press, defaults to -1
private int mProviderUid = -1; private int mProviderUid = -1;
@@ -42,7 +41,7 @@ public class BrowsedAuthenticationMetric {
// The status of this particular provider // The status of this particular provider
private int mProviderStatus = -1; private int mProviderStatus = -1;
// Indicates if this provider returned from the authentication entry query, default false // Indicates if this provider returned from the authentication entry query, default false
private boolean mQueryReturned = false; private boolean mAuthReturned = false;
// TODO(b/271135048) - Match the atom and provide a clean per provider session metric // TODO(b/271135048) - Match the atom and provide a clean per provider session metric
// encapsulation. // encapsulation.
@@ -84,12 +83,12 @@ public class BrowsedAuthenticationMetric {
mProviderStatus = providerStatus; mProviderStatus = providerStatus;
} }
public void setQueryReturned(boolean queryReturned) { public void setAuthReturned(boolean authReturned) {
mQueryReturned = queryReturned; mAuthReturned = authReturned;
} }
public boolean isQueryReturned() { public boolean isAuthReturned() {
return mQueryReturned; return mAuthReturned;
} }
public int getProviderStatus() { public int getProviderStatus() {

View File

@@ -24,7 +24,8 @@ import java.util.Map;
/** /**
* This will generate most of its data via using the information of {@link CandidatePhaseMetric} * 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. * across all the providers. This belongs to the metric flow where the calling app is known. It
* also contains {@link BrowsedAuthenticationMetric} data aggregated within.
*/ */
public class CandidateAggregateMetric { public class CandidateAggregateMetric {
@@ -34,6 +35,9 @@ public class CandidateAggregateMetric {
// Indicates if this provider returned from the candidate query phase, // Indicates if this provider returned from the candidate query phase,
// true if at least one provider returns validly, even if empty, default false // true if at least one provider returns validly, even if empty, default false
private boolean mQueryReturned = false; private boolean mQueryReturned = false;
// For reference, the initial log timestamp when the service started running the API call,
// defaults to -1
private long mServiceBeganTimeNanoseconds = -1;
// Indicates the total number of providers this aggregate captures information for, default 0 // Indicates the total number of providers this aggregate captures information for, default 0
private int mNumProviders = 0; private int mNumProviders = 0;
// Indicates if the authentication entry returned, true if at least one entry returns validly, // Indicates if the authentication entry returned, true if at least one entry returns validly,
@@ -47,6 +51,18 @@ public class CandidateAggregateMetric {
// The combined aggregate collective across the auth entry info // The combined aggregate collective across the auth entry info
private ResponseCollective mAggregateCollectiveAuth = private ResponseCollective mAggregateCollectiveAuth =
new ResponseCollective(Map.of(), Map.of()); new ResponseCollective(Map.of(), Map.of());
// The minimum of all the providers query start time, defaults to -1
private long mMinProviderTimestampNanoseconds = -1;
// The maximum of all the providers query finish time, defaults to -1
private long mMaxProviderTimestampNanoseconds = -1;
// The total number of failures across all the providers, defaults to 0
private int mTotalQueryFailures = 0;
// The map of all seen framework exceptions and their counts across all providers, default empty
private Map<String, Integer> mExceptionCountQuery = new LinkedHashMap<>();
// The total number of failures across all auth entries, defaults to 0
private int mTotalAuthFailures = 0;
// The map of all seen framework exceptions and their counts across auth entries, default empty
private Map<String, Integer> mExceptionCountAuth = new LinkedHashMap<>();
public CandidateAggregateMetric(int sessionIdTrackOne) { public CandidateAggregateMetric(int sessionIdTrackOne) {
mSessionIdProvider = sessionIdTrackOne; mSessionIdProvider = sessionIdTrackOne;
@@ -72,16 +88,33 @@ public class CandidateAggregateMetric {
Map<String, Integer> responseCountQuery = new LinkedHashMap<>(); Map<String, Integer> responseCountQuery = new LinkedHashMap<>();
Map<EntryEnum, Integer> entryCountQuery = new LinkedHashMap<>(); Map<EntryEnum, Integer> entryCountQuery = new LinkedHashMap<>();
var providerSessions = providers.values(); var providerSessions = providers.values();
long min_query_start = Integer.MAX_VALUE;
long max_query_end = Integer.MIN_VALUE;
for (var session : providerSessions) { for (var session : providerSessions) {
var sessionMetric = session.getProviderSessionMetric(); var sessionMetric = session.getProviderSessionMetric();
var candidateMetric = sessionMetric.getCandidatePhasePerProviderMetric(); var candidateMetric = sessionMetric.getCandidatePhasePerProviderMetric();
if (mServiceBeganTimeNanoseconds == -1) {
mServiceBeganTimeNanoseconds = candidateMetric.getServiceBeganTimeNanoseconds();
}
mQueryReturned = mQueryReturned || candidateMetric.isQueryReturned(); mQueryReturned = mQueryReturned || candidateMetric.isQueryReturned();
ResponseCollective candidateCollective = candidateMetric.getResponseCollective(); ResponseCollective candidateCollective = candidateMetric.getResponseCollective();
ResponseCollective.combineTypeCountMaps(responseCountQuery, ResponseCollective.combineTypeCountMaps(responseCountQuery,
candidateCollective.getResponseCountsMap()); candidateCollective.getResponseCountsMap());
ResponseCollective.combineTypeCountMaps(entryCountQuery, ResponseCollective.combineTypeCountMaps(entryCountQuery,
candidateCollective.getEntryCountsMap()); candidateCollective.getEntryCountsMap());
min_query_start = Math.min(min_query_start,
candidateMetric.getStartQueryTimeNanoseconds());
max_query_end = Math.max(max_query_end, candidateMetric
.getQueryFinishTimeNanoseconds());
mTotalQueryFailures += (candidateMetric.isHasException() ? 1 : 0);
if (!candidateMetric.getFrameworkException().isEmpty()) {
mExceptionCountQuery.put(candidateMetric.getFrameworkException(),
mExceptionCountQuery.getOrDefault(
candidateMetric.getFrameworkException(), 0) + 1);
} }
}
mMinProviderTimestampNanoseconds = min_query_start;
mMaxProviderTimestampNanoseconds = max_query_end;
mAggregateCollectiveQuery = new ResponseCollective(responseCountQuery, entryCountQuery); mAggregateCollectiveQuery = new ResponseCollective(responseCountQuery, entryCountQuery);
} }
@@ -95,12 +128,18 @@ public class CandidateAggregateMetric {
var authMetrics = sessionMetric.getBrowsedAuthenticationMetric(); var authMetrics = sessionMetric.getBrowsedAuthenticationMetric();
mNumAuthEntriesTapped += authMetrics.size(); mNumAuthEntriesTapped += authMetrics.size();
for (var authMetric : authMetrics) { for (var authMetric : authMetrics) {
mAuthReturned = mAuthReturned || authMetric.isQueryReturned(); mAuthReturned = mAuthReturned || authMetric.isAuthReturned();
ResponseCollective authCollective = authMetric.getAuthEntryCollective(); ResponseCollective authCollective = authMetric.getAuthEntryCollective();
ResponseCollective.combineTypeCountMaps(responseCountAuth, ResponseCollective.combineTypeCountMaps(responseCountAuth,
authCollective.getResponseCountsMap()); authCollective.getResponseCountsMap());
ResponseCollective.combineTypeCountMaps(entryCountAuth, ResponseCollective.combineTypeCountMaps(entryCountAuth,
authCollective.getEntryCountsMap()); authCollective.getEntryCountsMap());
mTotalQueryFailures += (authMetric.isHasException() ? 1 : 0);
if (!authMetric.getFrameworkException().isEmpty()) {
mExceptionCountQuery.put(authMetric.getFrameworkException(),
mExceptionCountQuery.getOrDefault(
authMetric.getFrameworkException(), 0) + 1);
}
} }
} }
mAggregateCollectiveAuth = new ResponseCollective(responseCountAuth, entryCountAuth); mAggregateCollectiveAuth = new ResponseCollective(responseCountAuth, entryCountAuth);
@@ -130,4 +169,67 @@ public class CandidateAggregateMetric {
public boolean isAuthReturned() { public boolean isAuthReturned() {
return mAuthReturned; return mAuthReturned;
} }
public long getMaxProviderTimestampNanoseconds() {
return mMaxProviderTimestampNanoseconds;
}
public long getMinProviderTimestampNanoseconds() {
return mMinProviderTimestampNanoseconds;
}
public int getTotalQueryFailures() {
return mTotalQueryFailures;
}
/**
* Returns the unique, deduped, exception classtypes for logging associated with this provider.
*
* @return a string array for deduped exception classtypes
*/
public String[] getUniqueExceptionStringsQuery() {
String[] result = new String[mExceptionCountQuery.keySet().size()];
mExceptionCountQuery.keySet().toArray(result);
return result;
}
/**
* Returns the unique, deduped, exception classtype counts for logging associated with this
* provider.
*
* @return a string array for deduped classtype exception counts
*/
public int[] getUniqueExceptionCountsQuery() {
return mExceptionCountQuery.values().stream().mapToInt(Integer::intValue).toArray();
}
/**
* Returns the unique, deduped, exception classtypes for logging associated with this provider
* for auth entries.
*
* @return a string array for deduped exception classtypes for auth entries
*/
public String[] getUniqueExceptionStringsAuth() {
String[] result = new String[mExceptionCountAuth.keySet().size()];
mExceptionCountAuth.keySet().toArray(result);
return result;
}
/**
* Returns the unique, deduped, exception classtype counts for logging associated with this
* provider for auth entries.
*
* @return a string array for deduped classtype exception counts for auth entries
*/
public int[] getUniqueExceptionCountsAuth() {
return mExceptionCountAuth.values().stream().mapToInt(Integer::intValue).toArray();
}
public long getServiceBeganTimeNanoseconds() {
return mServiceBeganTimeNanoseconds;
}
public int getTotalAuthFailures() {
return mTotalAuthFailures;
}
} }

View File

@@ -59,6 +59,8 @@ public class CandidatePhaseMetric {
// Stores the response credential information, as well as the response entry information which // Stores the response credential information, as well as the response entry information which
// by default, contains empty info // by default, contains empty info
private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of()); private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
// Indicates if this candidate is a primary provider, false by default
private boolean mIsPrimary = false;
public CandidatePhaseMetric(int sessionIdTrackTwo) { public CandidatePhaseMetric(int sessionIdTrackTwo) {
mSessionIdProvider = sessionIdTrackTwo; mSessionIdProvider = sessionIdTrackTwo;
@@ -185,4 +187,12 @@ public class CandidatePhaseMetric {
public String getFrameworkException() { public String getFrameworkException() {
return mFrameworkException; return mFrameworkException;
} }
public void setPrimary(boolean primary) {
mIsPrimary = primary;
}
public boolean isPrimary() {
return mIsPrimary;
}
} }

View File

@@ -76,6 +76,8 @@ public class ChosenProviderFinalPhaseMetric {
// Stores the response credential information, as well as the response entry information which // Stores the response credential information, as well as the response entry information which
// by default, contains empty info // by default, contains empty info
private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of()); private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
// Indicates if this chosen provider was the primary provider, false by default
private boolean mIsPrimary = false;
public ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider) { public ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider) {
@@ -292,4 +294,12 @@ public class ChosenProviderFinalPhaseMetric {
public int getSessionIdCaller() { public int getSessionIdCaller() {
return mSessionIdCaller; return mSessionIdCaller;
} }
public void setPrimary(boolean primary) {
mIsPrimary = primary;
}
public boolean isPrimary() {
return mIsPrimary;
}
} }

View File

@@ -100,8 +100,8 @@ public class ProviderSessionMetric {
*/ */
public void collectAuthenticationExceptionStatus(boolean hasException) { public void collectAuthenticationExceptionStatus(boolean hasException) {
try { try {
var mostRecentAuthenticationMetric = mBrowsedAuthenticationMetric BrowsedAuthenticationMetric mostRecentAuthenticationMetric =
.get(mBrowsedAuthenticationMetric.size() - 1); getUsedAuthenticationMetric();
mostRecentAuthenticationMetric.setHasException(hasException); mostRecentAuthenticationMetric.setHasException(hasException);
} catch (Exception e) { } catch (Exception e) {
Slog.i(TAG, "Error while setting authentication metric exception " + e); Slog.i(TAG, "Error while setting authentication metric exception " + e);
@@ -122,40 +122,44 @@ public class ProviderSessionMetric {
private void collectAuthEntryUpdate(boolean isFailureStatus, private void collectAuthEntryUpdate(boolean isFailureStatus,
boolean isCompletionStatus, int providerSessionUid) { boolean isCompletionStatus, int providerSessionUid) {
// TODO(b/271135048) - Mimic typical candidate update, but with authentication metric BrowsedAuthenticationMetric mostRecentAuthenticationMetric =
// Collect the final timestamps (and start timestamp), status, exceptions and the provider getUsedAuthenticationMetric();
// uid. This occurs typically *after* the collection is complete.
var mostRecentAuthenticationMetric = mBrowsedAuthenticationMetric
.get(mBrowsedAuthenticationMetric.size() - 1);
mostRecentAuthenticationMetric.setProviderUid(providerSessionUid); mostRecentAuthenticationMetric.setProviderUid(providerSessionUid);
// TODO(immediately) - add timestamps (no longer needed!!) but also update below values!
if (isFailureStatus) { if (isFailureStatus) {
mostRecentAuthenticationMetric.setQueryReturned(false); mostRecentAuthenticationMetric.setAuthReturned(false);
mostRecentAuthenticationMetric.setProviderStatus( mostRecentAuthenticationMetric.setProviderStatus(
ProviderStatusForMetrics.QUERY_FAILURE ProviderStatusForMetrics.QUERY_FAILURE
.getMetricCode()); .getMetricCode());
} else if (isCompletionStatus) { } else if (isCompletionStatus) {
mostRecentAuthenticationMetric.setQueryReturned(true); mostRecentAuthenticationMetric.setAuthReturned(true);
mostRecentAuthenticationMetric.setProviderStatus( mostRecentAuthenticationMetric.setProviderStatus(
ProviderStatusForMetrics.QUERY_SUCCESS ProviderStatusForMetrics.QUERY_SUCCESS
.getMetricCode()); .getMetricCode());
} }
} }
private BrowsedAuthenticationMetric getUsedAuthenticationMetric() {
return mBrowsedAuthenticationMetric
.get(mBrowsedAuthenticationMetric.size() - 1);
}
/** /**
* Used to collect metrics at the update stage when a candidate provider gives back an update. * Used to collect metrics at the update stage when a candidate provider gives back an update.
* *
* @param isFailureStatus indicates the candidate provider sent back a terminated response * @param isFailureStatus indicates the candidate provider sent back a terminated response
* @param isCompletionStatus indicates the candidate provider sent back a completion response * @param isCompletionStatus indicates the candidate provider sent back a completion response
* @param providerSessionUid the uid of the provider * @param providerSessionUid the uid of the provider
* @param isPrimary indicates if this candidate provider was the primary provider
*/ */
public void collectCandidateMetricUpdate(boolean isFailureStatus, public void collectCandidateMetricUpdate(boolean isFailureStatus,
boolean isCompletionStatus, int providerSessionUid, boolean isAuthEntry) { boolean isCompletionStatus, int providerSessionUid, boolean isAuthEntry,
boolean isPrimary) {
try { try {
if (isAuthEntry) { if (isAuthEntry) {
collectAuthEntryUpdate(isFailureStatus, isCompletionStatus, providerSessionUid); collectAuthEntryUpdate(isFailureStatus, isCompletionStatus, providerSessionUid);
return; return;
} }
mCandidatePhasePerProviderMetric.setPrimary(isPrimary);
mCandidatePhasePerProviderMetric.setCandidateUid(providerSessionUid); mCandidatePhasePerProviderMetric.setCandidateUid(providerSessionUid);
mCandidatePhasePerProviderMetric mCandidatePhasePerProviderMetric
.setQueryFinishTimeNanoseconds(System.nanoTime()); .setQueryFinishTimeNanoseconds(System.nanoTime());

View File

@@ -20,6 +20,7 @@ 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_EXCEPTION_CUT;
import static com.android.server.credentials.MetricUtilities.DELTA_RESPONSES_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.generateMetricKey;
import static com.android.server.credentials.MetricUtilities.logApiCalledAggregateCandidate;
import static com.android.server.credentials.MetricUtilities.logApiCalledAuthenticationMetric; import static com.android.server.credentials.MetricUtilities.logApiCalledAuthenticationMetric;
import static com.android.server.credentials.MetricUtilities.logApiCalledCandidateGetMetric; import static com.android.server.credentials.MetricUtilities.logApiCalledCandidateGetMetric;
import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase; import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase;
@@ -27,6 +28,7 @@ import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPh
import static com.android.server.credentials.MetricUtilities.logApiCalledNoUidFinal; import static com.android.server.credentials.MetricUtilities.logApiCalledNoUidFinal;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.content.ComponentName;
import android.credentials.GetCredentialRequest; import android.credentials.GetCredentialRequest;
import android.credentials.ui.UserSelectionDialogResult; import android.credentials.ui.UserSelectionDialogResult;
import android.util.Slog; import android.util.Slog;
@@ -279,6 +281,26 @@ public class RequestSessionMetric {
} }
} }
/**
* Used to update metrics when a response is received in a RequestSession.
*
* @param componentName the component name associated with the provider the response is for
*/
public void updateMetricsOnResponseReceived(Map<String, ProviderSession> providers,
ComponentName componentName, boolean isPrimary) {
try {
var chosenProviderSession = providers.get(componentName.flattenToString());
if (chosenProviderSession != null) {
ProviderSessionMetric providerSessionMetric =
chosenProviderSession.getProviderSessionMetric();
collectChosenMetricViaCandidateTransfer(providerSessionMetric
.getCandidatePhasePerProviderMetric(), isPrimary);
}
} catch (Exception e) {
Slog.i(TAG, "Exception upon candidate to chosen metric transfer: " + e);
}
}
/** /**
* Called by RequestSessions upon chosen metric determination. It's expected that most bits * Called by RequestSessions upon chosen metric determination. It's expected that most bits
* are transferred here. However, certain new information, such as the selected provider's final * are transferred here. However, certain new information, such as the selected provider's final
@@ -288,10 +310,13 @@ public class RequestSessionMetric {
* {@link com.android.internal.util.FrameworkStatsLog} metric generation. * {@link com.android.internal.util.FrameworkStatsLog} metric generation.
* *
* @param candidatePhaseMetric the componentName to associate with a provider * @param candidatePhaseMetric the componentName to associate with a provider
* @param isPrimary indicates that this chosen provider is the primary provider (or not)
*/ */
public void collectChosenMetricViaCandidateTransfer(CandidatePhaseMetric candidatePhaseMetric) { public void collectChosenMetricViaCandidateTransfer(CandidatePhaseMetric candidatePhaseMetric,
boolean isPrimary) {
try { try {
mChosenProviderFinalPhaseMetric.setChosenUid(candidatePhaseMetric.getCandidateUid()); mChosenProviderFinalPhaseMetric.setChosenUid(candidatePhaseMetric.getCandidateUid());
mChosenProviderFinalPhaseMetric.setPrimary(isPrimary);
mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds( mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds(
candidatePhaseMetric.getQueryLatencyMicroseconds()); candidatePhaseMetric.getQueryLatencyMicroseconds());
@@ -357,6 +382,7 @@ public class RequestSessionMetric {
public void logCandidateAggregateMetrics(Map<String, ProviderSession> providers) { public void logCandidateAggregateMetrics(Map<String, ProviderSession> providers) {
try { try {
mCandidateAggregateMetric.collectAverages(providers); mCandidateAggregateMetric.collectAverages(providers);
logApiCalledAggregateCandidate(mCandidateAggregateMetric, ++mSequenceCounter);
} catch (Exception e) { } catch (Exception e) {
Slog.i(TAG, "Unexpected error during aggregate candidate logging " + e); Slog.i(TAG, "Unexpected error during aggregate candidate logging " + e);
} }