Merge changes If8cf0831,Ib3203643,I8e7455dd into udc-dev
* changes: Sets up Final Phase Emit for Calling App Track Adds to Aggregate Candidate Metric query and count Candidate Aggregate Metrics Setup + sessId Focus
This commit is contained in:
@@ -30,6 +30,8 @@ import android.os.RemoteException;
|
||||
import android.service.credentials.CallingAppInfo;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.credentials.metrics.ProviderSessionMetric;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -93,9 +95,12 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
|
||||
public void onFinalResponseReceived(
|
||||
ComponentName componentName,
|
||||
Void response) {
|
||||
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(
|
||||
mProviders.get(componentName.flattenToString()).mProviderSessionMetric
|
||||
.getCandidatePhasePerProviderMetric());
|
||||
if (mProviders.get(componentName.flattenToString()) != null) {
|
||||
ProviderSessionMetric providerSessionMetric =
|
||||
mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
|
||||
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
|
||||
.getCandidatePhasePerProviderMetric());
|
||||
}
|
||||
respondToClientWithResponseAndFinish(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.service.credentials.CallingAppInfo;
|
||||
import android.service.credentials.PermissionUtils;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.credentials.metrics.ProviderSessionMetric;
|
||||
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -131,9 +132,12 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
|
||||
@Nullable CreateCredentialResponse response) {
|
||||
Slog.i(TAG, "Final credential received from: " + componentName.flattenToString());
|
||||
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime());
|
||||
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(mProviders.get(
|
||||
componentName.flattenToString()).mProviderSessionMetric
|
||||
.getCandidatePhasePerProviderMetric());
|
||||
if (mProviders.get(componentName.flattenToString()) != null) {
|
||||
ProviderSessionMetric providerSessionMetric =
|
||||
mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
|
||||
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
|
||||
.getCandidatePhasePerProviderMetric());
|
||||
}
|
||||
if (response != null) {
|
||||
mRequestSessionMetric.collectChosenProviderStatus(
|
||||
ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode());
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.RemoteException;
|
||||
import android.service.credentials.CallingAppInfo;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.credentials.metrics.ProviderSessionMetric;
|
||||
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -130,9 +131,12 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
|
||||
@Nullable GetCredentialResponse response) {
|
||||
Slog.i(TAG, "onFinalResponseReceived from: " + componentName.flattenToString());
|
||||
mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime());
|
||||
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(
|
||||
mProviders.get(componentName.flattenToString())
|
||||
.mProviderSessionMetric.getCandidatePhasePerProviderMetric());
|
||||
if (mProviders.get(componentName.flattenToString()) != null) {
|
||||
ProviderSessionMetric providerSessionMetric =
|
||||
mProviders.get(componentName.flattenToString()).mProviderSessionMetric;
|
||||
mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(providerSessionMetric
|
||||
.getCandidatePhasePerProviderMetric());
|
||||
}
|
||||
if (response != null) {
|
||||
mRequestSessionMetric.collectChosenProviderStatus(
|
||||
ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode());
|
||||
|
||||
@@ -24,12 +24,14 @@ 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.CandidateAggregateMetric;
|
||||
import com.android.server.credentials.metrics.CandidateBrowsingPhaseMetric;
|
||||
import com.android.server.credentials.metrics.CandidatePhaseMetric;
|
||||
import com.android.server.credentials.metrics.ChosenProviderFinalPhaseMetric;
|
||||
import com.android.server.credentials.metrics.EntryEnum;
|
||||
import com.android.server.credentials.metrics.InitialPhaseMetric;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -78,6 +80,15 @@ public class MetricUtilities {
|
||||
return sessUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to help generate random sequences for local sessions, in the time-scale of credential
|
||||
* manager flows.
|
||||
* @return a high entropy int useful to use in reasonable time-frame sessions.
|
||||
*/
|
||||
public static int getHighlyUniqueInteger() {
|
||||
return new SecureRandom().nextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given any two timestamps in nanoseconds, this gets the difference and converts to
|
||||
* milliseconds. Assumes the difference is not larger than the maximum int size.
|
||||
@@ -130,7 +141,7 @@ public class MetricUtilities {
|
||||
index++;
|
||||
}
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_FINAL_PHASE_REPORTED,
|
||||
/* session_id */ finalPhaseMetric.getSessionId(),
|
||||
/* session_id */ finalPhaseMetric.getSessionIdProvider(),
|
||||
/* sequence_num */ emitSequenceId,
|
||||
/* ui_returned_final_start */ finalPhaseMetric.isUiReturned(),
|
||||
/* chosen_provider_uid */ finalPhaseMetric.getChosenUid(),
|
||||
@@ -170,8 +181,7 @@ public class MetricUtilities {
|
||||
finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
|
||||
/* framework_exception_unique_classtype */
|
||||
finalPhaseMetric.getFrameworkException(),
|
||||
/* primary_indicated */
|
||||
false
|
||||
/* primary_indicated */ false
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unexpected error during final provider uid emit: " + e);
|
||||
@@ -215,7 +225,7 @@ public class MetricUtilities {
|
||||
CandidatePhaseMetric metric = session.mProviderSessionMetric
|
||||
.getCandidatePhasePerProviderMetric();
|
||||
if (sessionId == -1) {
|
||||
sessionId = metric.getSessionId();
|
||||
sessionId = metric.getSessionIdProvider();
|
||||
}
|
||||
if (!queryReturned) {
|
||||
queryReturned = metric.isQueryReturned();
|
||||
@@ -319,7 +329,7 @@ public class MetricUtilities {
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_INIT_PHASE_REPORTED,
|
||||
/* api_name */ initialPhaseMetric.getApiName(),
|
||||
/* caller_uid */ initialPhaseMetric.getCallerUid(),
|
||||
/* session_id */ initialPhaseMetric.getSessionId(),
|
||||
/* session_id */ initialPhaseMetric.getSessionIdCaller(),
|
||||
/* sequence_num */ sequenceNum,
|
||||
/* initial_timestamp_reference_nanoseconds */
|
||||
initialPhaseMetric.getCredentialServiceStartedTimeNanoseconds(),
|
||||
@@ -336,4 +346,129 @@ public class MetricUtilities {
|
||||
Slog.w(TAG, "Unexpected error during initial metric emit: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A logging utility focused on track 1, where the calling app is known. This captures all
|
||||
* aggregate information for the candidate phase.
|
||||
*
|
||||
* @param candidateAggregateMetric the aggregate candidate metric information collected
|
||||
* @param sequenceNum the sequence number for this api call session emit
|
||||
*/
|
||||
public static void logApiCalledAggregateCandidate(
|
||||
CandidateAggregateMetric candidateAggregateMetric,
|
||||
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
|
||||
);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unexpected error during metric logging: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A logging utility used primarily for the final phase of the current metric setup for track 1.
|
||||
*
|
||||
* @param finalPhaseMetric the coalesced data of the chosen provider
|
||||
* @param browsingPhaseMetrics the coalesced data of the browsing phase
|
||||
* @param apiStatus the final status of this particular api call
|
||||
* @param emitSequenceId an emitted sequence id for the current session
|
||||
*/
|
||||
public static void logApiCalledNoUidFinal(ChosenProviderFinalPhaseMetric finalPhaseMetric,
|
||||
List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus,
|
||||
int emitSequenceId) {
|
||||
try {
|
||||
if (!LOG_FLAG) {
|
||||
return;
|
||||
}
|
||||
int browsedSize = browsingPhaseMetrics.size();
|
||||
int[] browsedClickedEntries = new int[browsedSize];
|
||||
int[] browsedProviderUid = new int[browsedSize];
|
||||
int index = 0;
|
||||
for (CandidateBrowsingPhaseMetric metric : browsingPhaseMetrics) {
|
||||
browsedClickedEntries[index] = metric.getEntryEnum();
|
||||
browsedProviderUid[index] = metric.getProviderUid();
|
||||
index++;
|
||||
}
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_FINALNOUID_REPORTED,
|
||||
/* session_id */ finalPhaseMetric.getSessionIdCaller(),
|
||||
/* sequence_num */ emitSequenceId,
|
||||
/* ui_returned_final_start */ finalPhaseMetric.isUiReturned(),
|
||||
/* chosen_provider_query_start_timestamp_microseconds */
|
||||
finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
|
||||
.getQueryStartTimeNanoseconds()),
|
||||
/* chosen_provider_query_end_timestamp_microseconds */
|
||||
finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
|
||||
.getQueryEndTimeNanoseconds()),
|
||||
/* chosen_provider_ui_invoked_timestamp_microseconds */
|
||||
finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
|
||||
.getUiCallStartTimeNanoseconds()),
|
||||
/* chosen_provider_ui_finished_timestamp_microseconds */
|
||||
finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
|
||||
.getUiCallEndTimeNanoseconds()),
|
||||
/* chosen_provider_finished_timestamp_microseconds */
|
||||
finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
|
||||
.getFinalFinishTimeNanoseconds()),
|
||||
/* chosen_provider_status */ finalPhaseMetric.getChosenProviderStatus(),
|
||||
/* chosen_provider_has_exception */ finalPhaseMetric.isHasException(),
|
||||
/* unique_entries */
|
||||
finalPhaseMetric.getResponseCollective().getUniqueEntries(),
|
||||
/* per_entry_counts */
|
||||
finalPhaseMetric.getResponseCollective().getUniqueEntryCounts(),
|
||||
/* unique_response_classtypes */
|
||||
finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(),
|
||||
/* per_classtype_counts */
|
||||
finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
|
||||
/* framework_exception_unique_classtype */
|
||||
finalPhaseMetric.getFrameworkException(),
|
||||
/* clicked_entries */ browsedClickedEntries,
|
||||
/* provider_of_clicked_entry */ browsedProviderUid,
|
||||
/* api_status */ apiStatus,
|
||||
/* primary_indicated */ false
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unexpected error during metric logging: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -193,11 +193,11 @@ public final class ProviderCreateSession extends ProviderSession<
|
||||
mProviderResponseDataHandler.addResponseContent(response.getCreateEntries(),
|
||||
response.getRemoteCreateEntry());
|
||||
if (mProviderResponseDataHandler.isEmptyResponse(response)) {
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response);
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
|
||||
updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE,
|
||||
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
|
||||
} else {
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response);
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
|
||||
updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED,
|
||||
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
|
||||
}
|
||||
|
||||
@@ -433,6 +433,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
|
||||
BeginGetCredentialResponse response = PendingIntentResultHandler
|
||||
.extractResponseContent(providerPendingIntentResponse
|
||||
.getResultData());
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/true);
|
||||
if (response != null && !mProviderResponseDataHandler.isEmptyResponse(response)) {
|
||||
addToInitialRemoteResponse(response, /*isInitialResponse=*/ false);
|
||||
// Additional content received is in the form of new response content.
|
||||
@@ -470,12 +471,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
|
||||
addToInitialRemoteResponse(response, /*isInitialResponse=*/true);
|
||||
// Log the data.
|
||||
if (mProviderResponseDataHandler.isEmptyResponse(response)) {
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response);
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
|
||||
updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE,
|
||||
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
|
||||
return;
|
||||
}
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response);
|
||||
mProviderSessionMetric.collectCandidateEntryMetrics(response, /*isAuthEntry*/false);
|
||||
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED,
|
||||
/*source=*/ CredentialsSource.REMOTE_PROVIDER);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public abstract class ProviderSession<T, R>
|
||||
@NonNull
|
||||
protected Boolean mProviderResponseSet = false;
|
||||
@NonNull
|
||||
protected final ProviderSessionMetric mProviderSessionMetric = new ProviderSessionMetric();
|
||||
protected final ProviderSessionMetric mProviderSessionMetric;
|
||||
@NonNull
|
||||
private int mProviderSessionUid;
|
||||
|
||||
@@ -113,6 +113,13 @@ public abstract class ProviderSession<T, R>
|
||||
return status == Status.COMPLETE || status == Status.EMPTY_RESPONSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives access to the objects metric collectors.
|
||||
*/
|
||||
public ProviderSessionMetric getProviderSessionMetric() {
|
||||
return this.mProviderSessionMetric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any class that wishes to get a callback when a particular
|
||||
* provider session's status changes. Typically, implemented by the {@link RequestSession}
|
||||
@@ -147,6 +154,8 @@ public abstract class ProviderSession<T, R>
|
||||
mComponentName = componentName;
|
||||
mRemoteCredentialService = remoteCredentialService;
|
||||
mProviderSessionUid = MetricUtilities.getPackageUid(mContext, mComponentName);
|
||||
mProviderSessionMetric = new ProviderSessionMetric(
|
||||
((RequestSession) mCallbacks).mRequestSessionMetric.getSessionIdTrackTwo());
|
||||
}
|
||||
|
||||
/** Provider status at various states of the provider session. */
|
||||
@@ -206,7 +215,8 @@ public abstract class ProviderSession<T, R>
|
||||
CredentialsSource source) {
|
||||
setStatus(status);
|
||||
mProviderSessionMetric.collectCandidateMetricUpdate(isTerminatingStatus(status),
|
||||
isCompletionStatus(status), mProviderSessionUid);
|
||||
isCompletionStatus(status), mProviderSessionUid,
|
||||
source == CredentialsSource.AUTH_ENTRY);
|
||||
mCallbacks.onProviderStatusChanged(status, mComponentName, source);
|
||||
}
|
||||
/** Common method that transfers metrics from the init phase to candidates */
|
||||
|
||||
@@ -75,6 +75,8 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
|
||||
protected final Handler mHandler;
|
||||
@UserIdInt
|
||||
protected final int mUserId;
|
||||
|
||||
protected final int mUniqueSessionInteger;
|
||||
private final int mCallingUid;
|
||||
@NonNull
|
||||
protected final CallingAppInfo mClientAppInfo;
|
||||
@@ -82,7 +84,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
|
||||
protected final CancellationSignal mCancellationSignal;
|
||||
|
||||
protected final Map<String, ProviderSession> mProviders = new ConcurrentHashMap<>();
|
||||
protected final RequestSessionMetric mRequestSessionMetric = new RequestSessionMetric();
|
||||
protected final RequestSessionMetric mRequestSessionMetric;
|
||||
protected final String mHybridService;
|
||||
|
||||
protected final Object mLock;
|
||||
@@ -132,7 +134,10 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
|
||||
mUserId, this, mEnabledProviders);
|
||||
mHybridService = context.getResources().getString(
|
||||
R.string.config_defaultCredentialManagerHybridService);
|
||||
mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId,
|
||||
mUniqueSessionInteger = MetricUtilities.getHighlyUniqueInteger();
|
||||
mRequestSessionMetric = new RequestSessionMetric(mUniqueSessionInteger,
|
||||
MetricUtilities.getHighlyUniqueInteger());
|
||||
mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted,
|
||||
mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
|
||||
setCancellationListener();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.credentials.metrics;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
// The session id of this provider known flow related metric
|
||||
private final int mSessionIdProvider;
|
||||
// TODO(b/271135048) - Match the atom and provide a clean per provider session metric
|
||||
// encapsulation.
|
||||
|
||||
public BrowsedAuthenticationMetric(int sessionIdProvider) {
|
||||
mSessionIdProvider = sessionIdProvider;
|
||||
}
|
||||
|
||||
public int getSessionIdProvider() {
|
||||
return mSessionIdProvider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.credentials.metrics;
|
||||
|
||||
import com.android.server.credentials.ProviderSession;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
private boolean mQueryReturned = false;
|
||||
// Indicates the total number of providers this aggregate captures information for, default 0
|
||||
private int mNumProviders = 0;
|
||||
// Indicates the total number of authentication entries that were tapped in aggregate, default 0
|
||||
private int mNumAuthEntriesTapped = 0;
|
||||
|
||||
public CandidateAggregateMetric(int sessionIdTrackOne) {
|
||||
mSessionIdProvider = sessionIdTrackOne;
|
||||
}
|
||||
|
||||
public int getSessionIdProvider() {
|
||||
return mSessionIdProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will take all the candidate data captured and aggregate that information.
|
||||
* TODO(b/271135048) : Add on authentication entry outputs from track 2 here as well once
|
||||
* generated
|
||||
* @param providers the providers associated with the candidate flow
|
||||
*/
|
||||
public void collectAverages(Map<String, ProviderSession> providers) {
|
||||
// TODO(b/271135048) : Complete this method
|
||||
mNumProviders = providers.size();
|
||||
var providerSessions = providers.values();
|
||||
for (var session : providerSessions) {
|
||||
var metric = session.getProviderSessionMetric();
|
||||
mQueryReturned = mQueryReturned || metric
|
||||
.mCandidatePhasePerProviderMetric.isQueryReturned();
|
||||
}
|
||||
}
|
||||
|
||||
public int getNumProviders() {
|
||||
return mNumProviders;
|
||||
}
|
||||
|
||||
public boolean isQueryReturned() {
|
||||
return mQueryReturned;
|
||||
}
|
||||
|
||||
public int getNumAuthEntriesTapped() {
|
||||
return mNumAuthEntriesTapped;
|
||||
}
|
||||
}
|
||||
@@ -27,23 +27,11 @@ package com.android.server.credentials.metrics;
|
||||
* though collection will begin in the candidate phase when the user begins browsing options.
|
||||
*/
|
||||
public class CandidateBrowsingPhaseMetric {
|
||||
// The session id associated with the API Call this candidate provider is a part of, default -1
|
||||
private int mSessionId = -1;
|
||||
// The EntryEnum that was pressed, defaults to -1
|
||||
private int mEntryEnum = EntryEnum.UNKNOWN.getMetricCode();
|
||||
// The provider associated with the press, defaults to -1
|
||||
private int mProviderUid = -1;
|
||||
|
||||
/* -- The session ID -- */
|
||||
|
||||
public void setSessionId(int sessionId) {
|
||||
mSessionId = sessionId;
|
||||
}
|
||||
|
||||
public int getSessionId() {
|
||||
return mSessionId;
|
||||
}
|
||||
|
||||
/* -- The Entry of this tap -- */
|
||||
|
||||
public void setEntryEnum(int entryEnum) {
|
||||
|
||||
@@ -32,8 +32,8 @@ import java.util.Map;
|
||||
public class CandidatePhaseMetric {
|
||||
|
||||
private static final String TAG = "CandidateProviderMetric";
|
||||
// The session id of this provider, default set to -1
|
||||
private int mSessionId = -1;
|
||||
// The session id of this provider metric
|
||||
private final int mSessionIdProvider;
|
||||
// Indicates if this provider returned from the query phase, default false
|
||||
private boolean mQueryReturned = false;
|
||||
|
||||
@@ -60,7 +60,8 @@ public class CandidatePhaseMetric {
|
||||
// by default, contains empty info
|
||||
private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
|
||||
|
||||
public CandidatePhaseMetric() {
|
||||
public CandidatePhaseMetric(int sessionIdTrackTwo) {
|
||||
mSessionIdProvider = sessionIdTrackTwo;
|
||||
}
|
||||
|
||||
/* ---------- Latencies ---------- */
|
||||
@@ -142,12 +143,8 @@ public class CandidatePhaseMetric {
|
||||
|
||||
/* -------------- Session Id ---------------- */
|
||||
|
||||
public void setSessionId(int sessionId) {
|
||||
mSessionId = sessionId;
|
||||
}
|
||||
|
||||
public int getSessionId() {
|
||||
return mSessionId;
|
||||
public int getSessionIdProvider() {
|
||||
return mSessionIdProvider;
|
||||
}
|
||||
|
||||
/* -------------- Query Returned Status ---------------- */
|
||||
|
||||
@@ -32,8 +32,12 @@ import java.util.Map;
|
||||
*/
|
||||
public class ChosenProviderFinalPhaseMetric {
|
||||
private static final String TAG = "ChosenFinalPhaseMetric";
|
||||
// The session id associated with this API call, used to unite split emits
|
||||
private int mSessionId = -1;
|
||||
// The session id associated with this API call, used to unite split emits, for the flow
|
||||
// where we know the calling app
|
||||
private final int mSessionIdCaller;
|
||||
// The session id associated with this API call, used to unite split emits, for the flow
|
||||
// where we know the provider apps
|
||||
private final int mSessionIdProvider;
|
||||
// Reveals if the UI was returned, false by default
|
||||
private boolean mUiReturned = false;
|
||||
private int mChosenUid = -1;
|
||||
@@ -74,7 +78,9 @@ public class ChosenProviderFinalPhaseMetric {
|
||||
private ResponseCollective mResponseCollective = new ResponseCollective(Map.of(), Map.of());
|
||||
|
||||
|
||||
public ChosenProviderFinalPhaseMetric() {
|
||||
public ChosenProviderFinalPhaseMetric(int sessionIdCaller, int sessionIdProvider) {
|
||||
mSessionIdCaller = sessionIdCaller;
|
||||
mSessionIdProvider = sessionIdProvider;
|
||||
}
|
||||
|
||||
/* ------------------- UID ------------------- */
|
||||
@@ -237,12 +243,8 @@ public class ChosenProviderFinalPhaseMetric {
|
||||
|
||||
/* ----------- Session ID -------------- */
|
||||
|
||||
public void setSessionId(int sessionId) {
|
||||
mSessionId = sessionId;
|
||||
}
|
||||
|
||||
public int getSessionId() {
|
||||
return mSessionId;
|
||||
public int getSessionIdProvider() {
|
||||
return mSessionIdProvider;
|
||||
}
|
||||
|
||||
/* ----------- UI Returned Successfully -------------- */
|
||||
@@ -284,4 +286,10 @@ public class ChosenProviderFinalPhaseMetric {
|
||||
public String getFrameworkException() {
|
||||
return mFrameworkException;
|
||||
}
|
||||
|
||||
/* -------------- Session ID for Track One (Known Calling App) ---------------- */
|
||||
|
||||
public int getSessionIdCaller() {
|
||||
return mSessionIdCaller;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ public class InitialPhaseMetric {
|
||||
private int mApiName = ApiName.UNKNOWN.getMetricCode();
|
||||
// The caller uid of the calling application, default to -1
|
||||
private int mCallerUid = -1;
|
||||
// The session id to unite multiple atom emits, default to -1
|
||||
private int mSessionId = -1;
|
||||
// The session id to unite multiple atom emits
|
||||
private final int mSessionIdCaller;
|
||||
|
||||
// Raw timestamps in nanoseconds, *the only* one logged as such (i.e. 64 bits) since it is a
|
||||
// reference point.
|
||||
@@ -50,7 +50,8 @@ public class InitialPhaseMetric {
|
||||
private Map<String, Integer> mRequestCounts = new LinkedHashMap<>();
|
||||
|
||||
|
||||
public InitialPhaseMetric() {
|
||||
public InitialPhaseMetric(int sessionIdTrackOne) {
|
||||
mSessionIdCaller = sessionIdTrackOne;
|
||||
}
|
||||
|
||||
/* ---------- Latencies ---------- */
|
||||
@@ -105,12 +106,8 @@ public class InitialPhaseMetric {
|
||||
|
||||
/* ------ SessionId ------ */
|
||||
|
||||
public void setSessionId(int sessionId) {
|
||||
mSessionId = sessionId;
|
||||
}
|
||||
|
||||
public int getSessionId() {
|
||||
return mSessionId;
|
||||
public int getSessionIdCaller() {
|
||||
return mSessionIdCaller;
|
||||
}
|
||||
|
||||
/* ------ Count Request Class Types ------ */
|
||||
|
||||
@@ -44,10 +44,17 @@ public class ProviderSessionMetric {
|
||||
|
||||
// Specific candidate provider metric for the provider this session handles
|
||||
@NonNull
|
||||
protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric =
|
||||
new CandidatePhaseMetric();
|
||||
protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric;
|
||||
|
||||
public ProviderSessionMetric() {}
|
||||
// IFF there was an authentication entry clicked, this stores all required information for
|
||||
// that event. This is for the 'get' flow.
|
||||
@NonNull
|
||||
protected final BrowsedAuthenticationMetric mBrowsedAuthenticationMetric;
|
||||
|
||||
public ProviderSessionMetric(int sessionIdTrackTwo) {
|
||||
mCandidatePhasePerProviderMetric = new CandidatePhaseMetric(sessionIdTrackTwo);
|
||||
mBrowsedAuthenticationMetric = new BrowsedAuthenticationMetric(sessionIdTrackTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the candidate provider phase metric and the data it contains.
|
||||
@@ -56,6 +63,7 @@ public class ProviderSessionMetric {
|
||||
return mCandidatePhasePerProviderMetric;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This collects for ProviderSessions, with respect to the candidate providers, whether
|
||||
* an exception occurred in the candidate call.
|
||||
@@ -78,6 +86,13 @@ public class ProviderSessionMetric {
|
||||
}
|
||||
}
|
||||
|
||||
private void collectAuthEntryUpdate(boolean isFailureStatus,
|
||||
boolean isCompletionStatus, int providerSessionUid) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to collect metrics at the update stage when a candidate provider gives back an update.
|
||||
*
|
||||
@@ -86,8 +101,12 @@ public class ProviderSessionMetric {
|
||||
* @param providerSessionUid the uid of the provider
|
||||
*/
|
||||
public void collectCandidateMetricUpdate(boolean isFailureStatus,
|
||||
boolean isCompletionStatus, int providerSessionUid) {
|
||||
boolean isCompletionStatus, int providerSessionUid, boolean isAuthEntry) {
|
||||
try {
|
||||
if (isAuthEntry) {
|
||||
collectAuthEntryUpdate(isFailureStatus, isCompletionStatus, providerSessionUid);
|
||||
return;
|
||||
}
|
||||
mCandidatePhasePerProviderMetric.setCandidateUid(providerSessionUid);
|
||||
mCandidatePhasePerProviderMetric
|
||||
.setQueryFinishTimeNanoseconds(System.nanoTime());
|
||||
@@ -119,7 +138,6 @@ public class ProviderSessionMetric {
|
||||
*/
|
||||
public void collectCandidateMetricSetupViaInitialMetric(InitialPhaseMetric initMetric) {
|
||||
try {
|
||||
mCandidatePhasePerProviderMetric.setSessionId(initMetric.getSessionId());
|
||||
mCandidatePhasePerProviderMetric.setServiceBeganTimeNanoseconds(
|
||||
initMetric.getCredentialServiceStartedTimeNanoseconds());
|
||||
mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime());
|
||||
@@ -133,13 +151,14 @@ public class ProviderSessionMetric {
|
||||
* purposes.
|
||||
*
|
||||
* @param response contains entries and data from the candidate provider responses
|
||||
* @param isAuthEntry indicates if this is an auth entry collection or not
|
||||
* @param <R> the response type associated with the API flow in progress
|
||||
*/
|
||||
public <R> void collectCandidateEntryMetrics(R response) {
|
||||
public <R> void collectCandidateEntryMetrics(R response, boolean isAuthEntry) {
|
||||
try {
|
||||
if (response instanceof BeginGetCredentialResponse) {
|
||||
beginGetCredentialResponseCollectionCandidateEntryMetrics(
|
||||
(BeginGetCredentialResponse) response);
|
||||
(BeginGetCredentialResponse) response, isAuthEntry);
|
||||
} else if (response instanceof BeginCreateCredentialResponse) {
|
||||
beginCreateCredentialResponseCollectionCandidateEntryMetrics(
|
||||
(BeginCreateCredentialResponse) response);
|
||||
@@ -198,7 +217,7 @@ public class ProviderSessionMetric {
|
||||
}
|
||||
|
||||
private void beginGetCredentialResponseCollectionCandidateEntryMetrics(
|
||||
BeginGetCredentialResponse response) {
|
||||
BeginGetCredentialResponse response, boolean isAuthEntry) {
|
||||
Map<EntryEnum, Integer> entryCounts = new LinkedHashMap<>();
|
||||
Map<String, Integer> responseCounts = new LinkedHashMap<>();
|
||||
int numCredEntries = response.getCredentialEntries().size();
|
||||
@@ -217,6 +236,11 @@ public class ProviderSessionMetric {
|
||||
});
|
||||
|
||||
ResponseCollective responseCollective = new ResponseCollective(responseCounts, entryCounts);
|
||||
mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
|
||||
|
||||
if (!isAuthEntry) {
|
||||
mCandidatePhasePerProviderMetric.setResponseCollective(responseCollective);
|
||||
} else {
|
||||
// TODO(b/immediately) - Add the auth entry get logic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,11 @@ 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.logApiCalledCandidatePhase;
|
||||
import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPhase;
|
||||
import static com.android.server.credentials.MetricUtilities.logApiCalledNoUidFinal;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.credentials.GetCredentialRequest;
|
||||
import android.credentials.ui.UserSelectionDialogResult;
|
||||
import android.os.IBinder;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.credentials.ProviderSession;
|
||||
@@ -48,13 +49,24 @@ public class RequestSessionMetric {
|
||||
// As emits occur in sequential order, increment this counter and utilize
|
||||
protected int mSequenceCounter = 0;
|
||||
|
||||
protected final InitialPhaseMetric mInitialPhaseMetric = new InitialPhaseMetric();
|
||||
protected final InitialPhaseMetric mInitialPhaseMetric;
|
||||
protected final ChosenProviderFinalPhaseMetric
|
||||
mChosenProviderFinalPhaseMetric = new 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
|
||||
protected final CandidateAggregateMetric mCandidateAggregateMetric;
|
||||
// Since track two is shared, this allows provider sessions to capture a metric-specific
|
||||
// session token for the flow where the provider is known
|
||||
private final int mSessionIdTrackTwo;
|
||||
|
||||
public RequestSessionMetric() {
|
||||
public RequestSessionMetric(int sessionIdTrackOne, int sessionIdTrackTwo) {
|
||||
mSessionIdTrackTwo = sessionIdTrackTwo;
|
||||
mInitialPhaseMetric = new InitialPhaseMetric(sessionIdTrackOne);
|
||||
mCandidateAggregateMetric = new CandidateAggregateMetric(sessionIdTrackOne);
|
||||
mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric(
|
||||
sessionIdTrackOne, sessionIdTrackTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,19 +87,26 @@ public class RequestSessionMetric {
|
||||
return mInitialPhaseMetric;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the aggregate candidate phase metrics associated with the request session
|
||||
*/
|
||||
public CandidateAggregateMetric getCandidateAggregateMetric() {
|
||||
return mCandidateAggregateMetric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upon starting the service, this fills the initial phase metric properly.
|
||||
*
|
||||
* @param timestampStarted the timestamp the service begins at
|
||||
* @param mRequestId the IBinder used to retrieve a unique id
|
||||
* @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, IBinder mRequestId,
|
||||
public void collectInitialPhaseMetricInfo(long timestampStarted,
|
||||
int mCallingUid, int metricCode) {
|
||||
try {
|
||||
mInitialPhaseMetric.setCredentialServiceStartedTimeNanoseconds(timestampStarted);
|
||||
mInitialPhaseMetric.setSessionId(mRequestId.hashCode());
|
||||
mInitialPhaseMetric.setCallerUid(mCallingUid);
|
||||
mInitialPhaseMetric.setApiName(metricCode);
|
||||
} catch (Exception e) {
|
||||
@@ -206,7 +225,6 @@ public class RequestSessionMetric {
|
||||
CandidatePhaseMetric selectedProviderPhaseMetric) {
|
||||
try {
|
||||
CandidateBrowsingPhaseMetric browsingPhaseMetric = new CandidateBrowsingPhaseMetric();
|
||||
browsingPhaseMetric.setSessionId(mInitialPhaseMetric.getSessionId());
|
||||
browsingPhaseMetric.setEntryEnum(
|
||||
EntryEnum.getMetricCodeFromString(selection.getEntryKey()));
|
||||
browsingPhaseMetric.setProviderUid(selectedProviderPhaseMetric.getCandidateUid());
|
||||
@@ -274,7 +292,6 @@ public class RequestSessionMetric {
|
||||
*/
|
||||
public void collectChosenMetricViaCandidateTransfer(CandidatePhaseMetric candidatePhaseMetric) {
|
||||
try {
|
||||
mChosenProviderFinalPhaseMetric.setSessionId(candidatePhaseMetric.getSessionId());
|
||||
mChosenProviderFinalPhaseMetric.setChosenUid(candidatePhaseMetric.getCandidateUid());
|
||||
|
||||
mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds(
|
||||
@@ -331,6 +348,20 @@ public class RequestSessionMetric {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles aggregate candidate phase metric emits in the RequestSession context, after the
|
||||
* candidate phase completes.
|
||||
*
|
||||
* @param providers a map with known providers and their held metric objects
|
||||
*/
|
||||
public void logCandidateAggregateMetrics(Map<String, ProviderSession> providers) {
|
||||
try {
|
||||
mCandidateAggregateMetric.collectAverages(providers);
|
||||
} catch (Exception e) {
|
||||
Slog.i(TAG, "Unexpected error during aggregate candidate logging " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the final logging for RequestSession context for the final phase.
|
||||
*
|
||||
@@ -341,9 +372,15 @@ public class RequestSessionMetric {
|
||||
logApiCalledFinalPhase(mChosenProviderFinalPhaseMetric, mCandidateBrowsingPhaseMetric,
|
||||
apiStatus,
|
||||
++mSequenceCounter);
|
||||
logApiCalledNoUidFinal(mChosenProviderFinalPhaseMetric, mCandidateBrowsingPhaseMetric,
|
||||
apiStatus,
|
||||
++mSequenceCounter);
|
||||
} catch (Exception e) {
|
||||
Slog.i(TAG, "Unexpected error during final metric emit: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getSessionIdTrackTwo() {
|
||||
return mSessionIdTrackTwo;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user