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