• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.credentials;
18 
19 import android.annotation.UserIdInt;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.credentials.CredentialManager;
24 import android.util.Slog;
25 
26 import com.android.internal.util.FrameworkStatsLog;
27 import com.android.server.credentials.metrics.ApiName;
28 import com.android.server.credentials.metrics.ApiStatus;
29 import com.android.server.credentials.metrics.BrowsedAuthenticationMetric;
30 import com.android.server.credentials.metrics.CandidateAggregateMetric;
31 import com.android.server.credentials.metrics.CandidateBrowsingPhaseMetric;
32 import com.android.server.credentials.metrics.CandidatePhaseMetric;
33 import com.android.server.credentials.metrics.ChosenProviderFinalPhaseMetric;
34 import com.android.server.credentials.metrics.EntryEnum;
35 import com.android.server.credentials.metrics.InitialPhaseMetric;
36 
37 import java.security.SecureRandom;
38 import java.util.List;
39 import java.util.Map;
40 
41 /**
42  * For all future metric additions, this will contain their names for local usage after importing
43  * from {@link com.android.internal.util.FrameworkStatsLog}.
44  */
45 public class MetricUtilities {
46     private static final boolean LOG_FLAG = true;
47 
48     private static final String TAG = CredentialManager.TAG;
49     public static final String USER_CANCELED_SUBSTRING = "TYPE_USER_CANCELED";
50     public static final int MIN_EMIT_WAIT_TIME_MS = 10;
51 
52     public static final int DEFAULT_INT_32 = -1;
53     public static final String DEFAULT_STRING = "";
54     public static final int[] DEFAULT_REPEATED_INT_32 = new int[0];
55     public static final String[] DEFAULT_REPEATED_STR = new String[0];
56     public static final boolean[] DEFAULT_REPEATED_BOOL = new boolean[0];
57     // Used for single count metric emits, such as singular amounts of various types
58     public static final int UNIT = 1;
59     // Used for zero count metric emits, such as zero amounts of various types
60     public static final int ZERO = 0;
61     // The number of characters at the end of the string to use as a key
62     public static final int DELTA_RESPONSES_CUT = 20;
63     // The cut for exception strings from the end - used to keep metrics small
64     public static final int DELTA_EXCEPTION_CUT = 30;
65 
66     /**
67      * This retrieves the uid of any package name, given a context and a component name for the
68      * package. By default, if the desired package uid cannot be found, it will fall back to a
69      * bogus uid.
70      *
71      * @return the uid of a given package
72      */
getPackageUid(Context context, ComponentName componentName, @UserIdInt int userId)73     protected static int getPackageUid(Context context, ComponentName componentName,
74             @UserIdInt int userId) {
75         if (componentName == null) {
76             return -1;
77         }
78         return getPackageUid(context, componentName.getPackageName(), userId);
79     }
80 
81     /** Returns the package uid, or -1 if not found. */
getPackageUid(Context context, String packageName, @UserIdInt int userId)82     public static int getPackageUid(Context context, String packageName,
83             @UserIdInt int userId) {
84         if (packageName == null) {
85             return -1;
86         }
87         try {
88             return context.getPackageManager().getPackageUidAsUser(packageName,
89                     PackageManager.PackageInfoFlags.of(0), userId);
90         } catch (Throwable t) {
91             Slog.i(TAG, "Couldn't find uid for " + packageName + ": " + t);
92             return -1;
93         }
94     }
95 
96     /**
97      * Used to help generate random sequences for local sessions, in the time-scale of credential
98      * manager flows.
99      * @return a high entropy int useful to use in reasonable time-frame sessions.
100      */
getHighlyUniqueInteger()101     public static int getHighlyUniqueInteger() {
102         return new SecureRandom().nextInt();
103     }
104 
105     /**
106      * Given any two timestamps in nanoseconds, this gets the difference and converts to
107      * milliseconds. Assumes the difference is not larger than the maximum int size.
108      *
109      * @param t2 the final timestamp
110      * @param t1 the initial timestamp
111      * @return the timestamp difference converted to microseconds
112      */
getMetricTimestampDifferenceMicroseconds(long t2, long t1)113     protected static int getMetricTimestampDifferenceMicroseconds(long t2, long t1) {
114         if (t2 - t1 > Integer.MAX_VALUE) {
115             Slog.i(TAG, "Input timestamps are too far apart and unsupported, "
116                     + "falling back to default int");
117             return DEFAULT_INT_32;
118         }
119         if (t2 < t1) {
120             Slog.i(TAG, "The timestamps aren't in expected order, falling back to default int");
121             return DEFAULT_INT_32;
122         }
123         return (int) ((t2 - t1) / 1000);
124     }
125 
126     /**
127      * Given the current design, we can designate how the strings in the backend should appear.
128      * This helper method lets us cut strings for our class types.
129      *
130      * @param classtype the classtype string we want to cut to generate a key
131      * @param deltaFromEnd the starting point from the end of the string we wish to begin at
132      * @return the cut up string key we want to use for metric logs
133      */
generateMetricKey(String classtype, int deltaFromEnd)134     public static String generateMetricKey(String classtype, int deltaFromEnd) {
135         return classtype.substring(classtype.length() - deltaFromEnd);
136     }
137 
138     /**
139      * A logging utility used primarily for the final phase of the current metric setup, focused on
140      * track 2, where the provider uid is known.
141      *
142      * @param finalPhaseMetric     the coalesced data of the chosen provider
143      * @param browsingPhaseMetrics the coalesced data of the browsing phase
144      * @param apiStatus            the final status of this particular api call
145      * @param emitSequenceId       an emitted sequence id for the current session
146      */
logApiCalledFinalPhase(ChosenProviderFinalPhaseMetric finalPhaseMetric, List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus, int emitSequenceId)147     public static void logApiCalledFinalPhase(ChosenProviderFinalPhaseMetric finalPhaseMetric,
148             List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus,
149             int emitSequenceId) {
150         try {
151             if (!LOG_FLAG) {
152                 return;
153             }
154             int browsedSize = browsingPhaseMetrics.size();
155             int[] browsedClickedEntries = new int[browsedSize];
156             int[] browsedProviderUid = new int[browsedSize];
157             int index = 0;
158             for (CandidateBrowsingPhaseMetric metric : browsingPhaseMetrics) {
159                 browsedClickedEntries[index] = metric.getEntryEnum();
160                 browsedProviderUid[index] = metric.getProviderUid();
161                 index++;
162             }
163             FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_FINAL_PHASE_REPORTED,
164                     /* session_id */ finalPhaseMetric.getSessionIdProvider(),
165                     /* sequence_num */ emitSequenceId,
166                     /* ui_returned_final_start */ finalPhaseMetric.isUiReturned(),
167                     /* chosen_provider_uid */ finalPhaseMetric.getChosenUid(),
168                     /* chosen_provider_query_start_timestamp_microseconds */
169                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
170                             .getQueryStartTimeNanoseconds()),
171                     /* chosen_provider_query_end_timestamp_microseconds */
172                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
173                             .getQueryEndTimeNanoseconds()),
174                     /* chosen_provider_ui_invoked_timestamp_microseconds */
175                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
176                             .getUiCallStartTimeNanoseconds()),
177                     /* chosen_provider_ui_finished_timestamp_microseconds */
178                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
179                             .getUiCallEndTimeNanoseconds()),
180                     /* chosen_provider_finished_timestamp_microseconds */
181                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
182                             .getFinalFinishTimeNanoseconds()),
183                     /* chosen_provider_status */ finalPhaseMetric.getChosenProviderStatus(),
184                     /* chosen_provider_has_exception */ finalPhaseMetric.isHasException(),
185                     /* chosen_provider_available_entries (deprecated) */ DEFAULT_REPEATED_INT_32,
186                     /* chosen_provider_action_entry_count (deprecated) */ DEFAULT_INT_32,
187                     /* chosen_provider_credential_entry_count (deprecated)*/DEFAULT_INT_32,
188                     /* chosen_provider_credential_entry_type_count (deprecated) */ DEFAULT_INT_32,
189                     /* chosen_provider_remote_entry_count (deprecated) */ DEFAULT_INT_32,
190                     /* chosen_provider_authentication_entry_count (deprecated) */ DEFAULT_INT_32,
191                     /* clicked_entries */ browsedClickedEntries,
192                     /* provider_of_clicked_entry */ browsedProviderUid,
193                     /* api_status */ apiStatus,
194                     /* unique_entries */
195                     finalPhaseMetric.getResponseCollective().getUniqueEntries(),
196                     /* per_entry_counts */
197                     finalPhaseMetric.getResponseCollective().getUniqueEntryCounts(),
198                     /* unique_response_classtypes */
199                     finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(),
200                     /* per_classtype_counts */
201                     finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
202                     /* framework_exception_unique_classtype */
203                     finalPhaseMetric.getFrameworkException(),
204                     /* primary_indicated */ finalPhaseMetric.isPrimary(),
205                     /* chosen_classtype */ finalPhaseMetric.getChosenClassType()
206             );
207         } catch (Exception e) {
208             Slog.w(TAG, "Unexpected error during final provider uid emit: " + e);
209         }
210     }
211 
212     /**
213      * This emits the authentication entry metrics for track 2, where the provider uid is known.
214      *
215      * @param authenticationMetric the authentication metric collection to emit with
216      * @param emitSequenceId       an emitted sequence id for the current session
217      */
logApiCalledAuthenticationMetric( BrowsedAuthenticationMetric authenticationMetric, int emitSequenceId)218     public static void logApiCalledAuthenticationMetric(
219             BrowsedAuthenticationMetric authenticationMetric,
220             int emitSequenceId) {
221         try {
222             if (!LOG_FLAG) {
223                 return;
224             }
225             FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_AUTH_CLICK_REPORTED,
226                     /* session_id */ authenticationMetric.getSessionIdProvider(),
227                     /* sequence_num */ emitSequenceId,
228                     /* chosen_provider_uid */ authenticationMetric.getProviderUid(),
229                     /* unique_response_classtypes */
230                     authenticationMetric.getAuthEntryCollective().getUniqueResponseStrings(),
231                     /* per_classtype_counts */
232                     authenticationMetric.getAuthEntryCollective().getUniqueResponseCounts(),
233                     /* unique_entries */
234                     authenticationMetric.getAuthEntryCollective().getUniqueEntries(),
235                     /* auth_per_entry_counts */
236                     authenticationMetric.getAuthEntryCollective().getUniqueEntryCounts(),
237                     /* framework_exception_unique_classtype */
238                     authenticationMetric.getFrameworkException(),
239                     /* exception_specified */ authenticationMetric.isHasException(),
240                     /* auth_provider_status */
241                     authenticationMetric.getProviderStatus(),
242                     /* query_returned */
243                     authenticationMetric.isAuthReturned()
244             );
245         } catch (Exception e) {
246             Slog.w(TAG, "Unexpected error during candidate auth metric logging: " + e);
247         }
248     }
249 
250     /**
251      * A logging utility used primarily for the candidate phase's get responses in the current
252      * metric setup. This helps avoid nested proto-files. This is primarily focused on track 2,
253      * where the provider uid is known. It ensures to run in a separate thread while emitting
254      * the multiple atoms to work with expected emit limits.
255      *
256      * @param providers      a map with known providers and their held metric objects
257      * @param emitSequenceId an emitted sequence id for the current session, that matches the
258      *                       candidate emit value, as these metrics belong with the candidates
259      */
logApiCalledCandidateGetMetric(Map<String, ProviderSession> providers, int emitSequenceId)260     public static void logApiCalledCandidateGetMetric(Map<String, ProviderSession> providers,
261             int emitSequenceId) {
262         try {
263             // TODO(b/274954697) : To queue format in future optimizations (metrics POC support)
264             if (!LOG_FLAG) {
265                 return;
266             }
267             var sessions = providers.values();
268             for (var session : sessions) {
269                 var metric = session.getProviderSessionMetric()
270                         .getCandidatePhasePerProviderMetric();
271                 FrameworkStatsLog.write(
272                         FrameworkStatsLog.CREDENTIAL_MANAGER_GET_REPORTED,
273                         /* session_id */ metric.getSessionIdProvider(),
274                         /* sequence_num */ emitSequenceId,
275                         /* candidate_provider_uid */ metric.getCandidateUid(),
276                         /* response_unique_classtypes */
277                         metric.getResponseCollective().getUniqueResponseStrings(),
278                         /* per_classtype_counts */
279                         metric.getResponseCollective().getUniqueResponseCounts()
280                 );
281             }
282         } catch (Exception e) {
283             Slog.w(TAG, "Unexpected error during candidate get metric logging: " + e);
284         }
285     }
286 
287 
288     /**
289      * A logging utility used primarily for the candidate phase of the current metric setup. This
290      * will primarily focus on track 2, where the session id is associated with known providers,
291      * but NOT the calling app.
292      *
293      * @param providers      a map with known providers and their held metric objects
294      * @param emitSequenceId an emitted sequence id for the current session
295      * @param initialPhaseMetric contains initial phase data to avoid repetition for candidate
296      *                           phase, track 2, logging
297      */
logApiCalledCandidatePhase(Map<String, ProviderSession> providers, int emitSequenceId, InitialPhaseMetric initialPhaseMetric)298     public static void logApiCalledCandidatePhase(Map<String, ProviderSession> providers,
299             int emitSequenceId, InitialPhaseMetric initialPhaseMetric) {
300         try {
301             if (!LOG_FLAG) {
302                 return;
303             }
304             var providerSessions = providers.values();
305             int providerSize = providerSessions.size();
306             int sessionId = -1;
307             boolean queryReturned = false;
308             int[] candidateUidList = new int[providerSize];
309             int[] candidateQueryStartTimeStampList = new int[providerSize];
310             int[] candidateQueryEndTimeStampList = new int[providerSize];
311             int[] candidateStatusList = new int[providerSize];
312             boolean[] candidateHasExceptionList = new boolean[providerSize];
313             int[] candidateTotalEntryCountList = new int[providerSize];
314             int[] candidateCredentialEntryCountList = new int[providerSize];
315             int[] candidateCredentialTypeCountList = new int[providerSize];
316             int[] candidateActionEntryCountList = new int[providerSize];
317             int[] candidateAuthEntryCountList = new int[providerSize];
318             int[] candidateRemoteEntryCountList = new int[providerSize];
319             String[] frameworkExceptionList = new String[providerSize];
320             boolean[] candidatePrimaryProviderList = new boolean[providerSize];
321             int index = 0;
322             for (var session : providerSessions) {
323                 CandidatePhaseMetric metric = session.mProviderSessionMetric
324                         .getCandidatePhasePerProviderMetric();
325                 if (sessionId == -1) {
326                     sessionId = metric.getSessionIdProvider();
327                 }
328                 if (!queryReturned) {
329                     queryReturned = metric.isQueryReturned();
330                 }
331                 candidateUidList[index] = metric.getCandidateUid();
332                 candidateQueryStartTimeStampList[index] =
333                         metric.getTimestampFromReferenceStartMicroseconds(
334                                 metric.getStartQueryTimeNanoseconds());
335                 candidateQueryEndTimeStampList[index] =
336                         metric.getTimestampFromReferenceStartMicroseconds(
337                                 metric.getQueryFinishTimeNanoseconds());
338                 candidateStatusList[index] = metric.getProviderQueryStatus();
339                 candidateHasExceptionList[index] = metric.isHasException();
340                 candidateTotalEntryCountList[index] = metric.getResponseCollective()
341                         .getNumEntriesTotal();
342                 candidateCredentialEntryCountList[index] = metric.getResponseCollective()
343                         .getCountForEntry(EntryEnum.CREDENTIAL_ENTRY);
344                 candidateCredentialTypeCountList[index] = metric.getResponseCollective()
345                         .getUniqueResponseStrings().length;
346                 candidateActionEntryCountList[index] = metric.getResponseCollective()
347                         .getCountForEntry(EntryEnum.ACTION_ENTRY);
348                 candidateAuthEntryCountList[index] = metric.getResponseCollective()
349                         .getCountForEntry(EntryEnum.AUTHENTICATION_ENTRY);
350                 candidateRemoteEntryCountList[index] = metric.getResponseCollective()
351                         .getCountForEntry(EntryEnum.REMOTE_ENTRY);
352                 frameworkExceptionList[index] = metric.getFrameworkException();
353                 candidatePrimaryProviderList[index] = metric.isPrimary();
354                 index++;
355             }
356             FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED,
357                     /* session_id */ sessionId,
358                     /* sequence_num */ emitSequenceId,
359                     /* query_returned */ queryReturned,
360                     /* candidate_provider_uid_list */ candidateUidList,
361                     /* candidate_provider_query_start_timestamp_microseconds */
362                     candidateQueryStartTimeStampList,
363                     /* candidate_provider_query_end_timestamp_microseconds */
364                     candidateQueryEndTimeStampList,
365                     /* candidate_provider_status */ candidateStatusList,
366                     /* candidate_provider_has_exception */ candidateHasExceptionList,
367                     /* candidate_provider_num_entries */ candidateTotalEntryCountList,
368                     /* candidate_provider_action_entry_count */ candidateActionEntryCountList,
369                     /* candidate_provider_credential_entry_count */
370                     candidateCredentialEntryCountList,
371                     /* candidate_provider_credential_entry_type_count */
372                     candidateCredentialTypeCountList,
373                     /* candidate_provider_remote_entry_count */ candidateRemoteEntryCountList,
374                     /* candidate_provider_authentication_entry_count */
375                     candidateAuthEntryCountList,
376                     /* framework_exception_per_provider */
377                     frameworkExceptionList,
378                     /* origin_specified originSpecified */
379                     initialPhaseMetric.isOriginSpecified(),
380                     /* request_unique_classtypes */
381                     initialPhaseMetric.getUniqueRequestStrings(),
382                     /* per_classtype_counts */
383                     initialPhaseMetric.getUniqueRequestCounts(),
384                     /* api_name */
385                     initialPhaseMetric.getApiName(),
386                     /* primary_candidates_indicated */
387                     candidatePrimaryProviderList,
388                     /* api_prepared */
389                     initialPhaseMetric.hasApiUsedPrepareFlow()
390             );
391         } catch (Exception e) {
392             Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e);
393         }
394     }
395 
396     /**
397      * This is useful just to record an API calls' final event, and for no other purpose.
398      *
399      * @param apiName    the api name to log
400      * @param apiStatus  the status to log
401      * @param callingUid the calling uid
402      */
logApiCalledSimpleV2(ApiName apiName, ApiStatus apiStatus, int callingUid)403     public static void logApiCalledSimpleV2(ApiName apiName, ApiStatus apiStatus,
404             int callingUid) {
405         try {
406             if (!LOG_FLAG) {
407                 return;
408             }
409             FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_APIV2_CALLED,
410                     /* api_name */apiName.getMetricCode(),
411                     /* caller_uid */ callingUid,
412                     /* api_status */ apiStatus.getMetricCode());
413         } catch (Exception e) {
414             Slog.w(TAG, "Unexpected error during simple v2 metric logging: " + e);
415         }
416     }
417 
418     /**
419      * Handles the metric emit for the initial phase.
420      *
421      * @param initialPhaseMetric contains all the data for this emit
422      * @param sequenceNum        the sequence number for this api call session emit
423      */
logApiCalledInitialPhase(InitialPhaseMetric initialPhaseMetric, int sequenceNum)424     public static void logApiCalledInitialPhase(InitialPhaseMetric initialPhaseMetric,
425             int sequenceNum) {
426         try {
427             if (!LOG_FLAG) {
428                 return;
429             }
430             FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_INIT_PHASE_REPORTED,
431                     /* api_name */ initialPhaseMetric.getApiName(),
432                     /* caller_uid */ initialPhaseMetric.getCallerUid(),
433                     /* session_id */ initialPhaseMetric.getSessionIdCaller(),
434                     /* sequence_num */ sequenceNum,
435                     /* initial_timestamp_reference_nanoseconds */
436                     initialPhaseMetric.getCredentialServiceStartedTimeNanoseconds(),
437                     /* count_credential_request_classtypes */
438                     initialPhaseMetric.getCountRequestClassType(),
439                     /* request_unique_classtypes */
440                     initialPhaseMetric.getUniqueRequestStrings(),
441                     /* per_classtype_counts */
442                     initialPhaseMetric.getUniqueRequestCounts(),
443                     /* origin_specified */
444                     initialPhaseMetric.isOriginSpecified(),
445                     /* autofill_session_id */
446                     initialPhaseMetric.getAutofillSessionId(),
447                     /* autofill_request_id */
448                     initialPhaseMetric.getAutofillRequestId(),
449                     /* api_prepared */
450                     initialPhaseMetric.hasApiUsedPrepareFlow()
451             );
452         } catch (Exception e) {
453             Slog.w(TAG, "Unexpected error during initial metric emit: " + e);
454         }
455     }
456 
457     /**
458      * A logging utility focused on track 1, where the calling app is known. This captures all
459      * aggregate information for the candidate phase.
460      *
461      * @param candidateAggregateMetric the aggregate candidate metric information collected
462      * @param sequenceNum the sequence number for this api call session emit
463      */
logApiCalledAggregateCandidate( CandidateAggregateMetric candidateAggregateMetric, int sequenceNum)464     public static void logApiCalledAggregateCandidate(
465             CandidateAggregateMetric candidateAggregateMetric,
466             int sequenceNum) {
467         try {
468             if (!LOG_FLAG) {
469                 return;
470             }
471             FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_TOTAL_REPORTED,
472                     /*session_id*/ candidateAggregateMetric.getSessionIdProvider(),
473                     /*sequence_num*/ sequenceNum,
474                     /*query_returned*/ candidateAggregateMetric.isQueryReturned(),
475                     /*num_query_providers*/ candidateAggregateMetric.getNumProviders(),
476                     /*min_query_start_timestamp_microseconds*/
477                     getMetricTimestampDifferenceMicroseconds(
478                             candidateAggregateMetric.getMinProviderTimestampNanoseconds(),
479                             candidateAggregateMetric.getServiceBeganTimeNanoseconds()),
480                     /*max_query_end_timestamp_microseconds*/
481                     getMetricTimestampDifferenceMicroseconds(
482                             candidateAggregateMetric.getMaxProviderTimestampNanoseconds(),
483                             candidateAggregateMetric.getServiceBeganTimeNanoseconds()),
484                     /*query_response_unique_classtypes*/
485                     candidateAggregateMetric.getAggregateCollectiveQuery()
486                             .getUniqueResponseStrings(),
487                     /*query_per_classtype_counts*/
488                     candidateAggregateMetric.getAggregateCollectiveQuery()
489                             .getUniqueResponseCounts(),
490                     /*query_unique_entries*/
491                     candidateAggregateMetric.getAggregateCollectiveQuery()
492                             .getUniqueEntries(),
493                     /*query_per_entry_counts*/
494                     candidateAggregateMetric.getAggregateCollectiveQuery()
495                             .getUniqueEntryCounts(),
496                     /*query_total_candidate_failure*/
497                     candidateAggregateMetric.getTotalQueryFailures(),
498                     /*query_framework_exception_unique_classtypes*/
499                     candidateAggregateMetric.getUniqueExceptionStringsQuery(),
500                     /*query_per_exception_classtype_counts*/
501                     candidateAggregateMetric.getUniqueExceptionCountsQuery(),
502                     /*auth_response_unique_classtypes*/
503                     candidateAggregateMetric.getAggregateCollectiveAuth()
504                             .getUniqueResponseStrings(),
505                     /*auth_per_classtype_counts*/
506                     candidateAggregateMetric.getAggregateCollectiveAuth()
507                             .getUniqueResponseCounts(),
508                     /*auth_unique_entries*/
509                     candidateAggregateMetric.getAggregateCollectiveAuth()
510                             .getUniqueEntries(),
511                     /*auth_per_entry_counts*/
512                     candidateAggregateMetric.getAggregateCollectiveAuth()
513                             .getUniqueEntryCounts(),
514                     /*auth_total_candidate_failure*/
515                     candidateAggregateMetric.getTotalAuthFailures(),
516                     /*auth_framework_exception_unique_classtypes*/
517                     candidateAggregateMetric.getUniqueExceptionStringsAuth(),
518                     /*auth_per_exception_classtype_counts*/
519                     candidateAggregateMetric.getUniqueExceptionCountsAuth(),
520                     /*num_auth_clicks*/
521                     candidateAggregateMetric.getNumAuthEntriesTapped(),
522                     /*auth_returned*/
523                     candidateAggregateMetric.isAuthReturned()
524             );
525         } catch (Exception e) {
526             Slog.w(TAG, "Unexpected error during total candidate metric logging: " + e);
527         }
528     }
529 
530     /**
531      * A logging utility used primarily for the final phase of the current metric setup for track 1.
532      *
533      * @param finalPhaseMetric     the coalesced data of the chosen provider
534      * @param browsingPhaseMetrics the coalesced data of the browsing phase
535      * @param apiStatus            the final status of this particular api call
536      * @param emitSequenceId       an emitted sequence id for the current session
537      */
logApiCalledNoUidFinal(ChosenProviderFinalPhaseMetric finalPhaseMetric, List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus, int emitSequenceId)538     public static void logApiCalledNoUidFinal(ChosenProviderFinalPhaseMetric finalPhaseMetric,
539             List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus,
540             int emitSequenceId) {
541         try {
542             if (!LOG_FLAG) {
543                 return;
544             }
545             int browsedSize = browsingPhaseMetrics.size();
546             int[] browsedClickedEntries = new int[browsedSize];
547             int[] browsedProviderUid = new int[browsedSize];
548             int index = 0;
549             for (CandidateBrowsingPhaseMetric metric : browsingPhaseMetrics) {
550                 browsedClickedEntries[index] = metric.getEntryEnum();
551                 browsedProviderUid[index] = DEFAULT_INT_32;
552                 index++;
553             }
554             FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_FINALNOUID_REPORTED,
555                     /* session_id */ finalPhaseMetric.getSessionIdCaller(),
556                     /* sequence_num */ emitSequenceId,
557                     /* ui_returned_final_start */ finalPhaseMetric.isUiReturned(),
558                     /* chosen_provider_query_start_timestamp_microseconds */
559                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
560                             .getQueryStartTimeNanoseconds()),
561                     /* chosen_provider_query_end_timestamp_microseconds */
562                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
563                             .getQueryEndTimeNanoseconds()),
564                     /* chosen_provider_ui_invoked_timestamp_microseconds */
565                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
566                             .getUiCallStartTimeNanoseconds()),
567                     /* chosen_provider_ui_finished_timestamp_microseconds */
568                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
569                             .getUiCallEndTimeNanoseconds()),
570                     /* chosen_provider_finished_timestamp_microseconds */
571                     finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric
572                             .getFinalFinishTimeNanoseconds()),
573                     /* chosen_provider_status */ finalPhaseMetric.getChosenProviderStatus(),
574                     /* chosen_provider_has_exception */ finalPhaseMetric.isHasException(),
575                     /* unique_entries */
576                     finalPhaseMetric.getResponseCollective().getUniqueEntries(),
577                     /* per_entry_counts */
578                     finalPhaseMetric.getResponseCollective().getUniqueEntryCounts(),
579                     /* unique_response_classtypes */
580                     finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(),
581                     /* per_classtype_counts */
582                     finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(),
583                     /* framework_exception_unique_classtype */
584                     finalPhaseMetric.getFrameworkException(),
585                     /* clicked_entries */ browsedClickedEntries,
586                     /* provider_of_clicked_entry */ browsedProviderUid,
587                     /* api_status */ apiStatus,
588                     /* primary_indicated */ finalPhaseMetric.isPrimary(),
589                     /* oem_credential_manager_ui_uid */ finalPhaseMetric.getOemUiUid(),
590                     /* fallback_credential_manager_ui_uid */ finalPhaseMetric.getFallbackUiUid(),
591                     /* oem_ui_usage_status */ finalPhaseMetric.getOemUiUsageStatus(),
592                     /* chosen_classtype */ finalPhaseMetric.getChosenClassType()
593             );
594         } catch (Exception e) {
595             Slog.w(TAG, "Unexpected error during final no uid metric logging: " + e);
596         }
597     }
598 
599 }
600