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:
Arpan Kaphle
2023-05-08 19:26:52 +00:00
committed by Android (Google) Code Review
16 changed files with 405 additions and 79 deletions

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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());

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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 ---------------- */

View File

@@ -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;
}
}

View File

@@ -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 ------ */

View File

@@ -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
}
}
}

View File

@@ -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;
}
}