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 ); 206 } catch (Exception e) { 207 Slog.w(TAG, "Unexpected error during final provider uid emit: " + e); 208 } 209 } 210 211 /** 212 * This emits the authentication entry metrics for track 2, where the provider uid is known. 213 * 214 * @param authenticationMetric the authentication metric collection to emit with 215 * @param emitSequenceId an emitted sequence id for the current session 216 */ logApiCalledAuthenticationMetric( BrowsedAuthenticationMetric authenticationMetric, int emitSequenceId)217 public static void logApiCalledAuthenticationMetric( 218 BrowsedAuthenticationMetric authenticationMetric, 219 int emitSequenceId) { 220 try { 221 if (!LOG_FLAG) { 222 return; 223 } 224 FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_AUTH_CLICK_REPORTED, 225 /* session_id */ authenticationMetric.getSessionIdProvider(), 226 /* sequence_num */ emitSequenceId, 227 /* chosen_provider_uid */ authenticationMetric.getProviderUid(), 228 /* unique_response_classtypes */ 229 authenticationMetric.getAuthEntryCollective().getUniqueResponseStrings(), 230 /* per_classtype_counts */ 231 authenticationMetric.getAuthEntryCollective().getUniqueResponseCounts(), 232 /* unique_entries */ 233 authenticationMetric.getAuthEntryCollective().getUniqueEntries(), 234 /* auth_per_entry_counts */ 235 authenticationMetric.getAuthEntryCollective().getUniqueEntryCounts(), 236 /* framework_exception_unique_classtype */ 237 authenticationMetric.getFrameworkException(), 238 /* exception_specified */ authenticationMetric.isHasException(), 239 /* auth_provider_status */ 240 authenticationMetric.getProviderStatus(), 241 /* query_returned */ 242 authenticationMetric.isAuthReturned() 243 ); 244 } catch (Exception e) { 245 Slog.w(TAG, "Unexpected error during candidate auth metric logging: " + e); 246 } 247 } 248 249 /** 250 * A logging utility used primarily for the candidate phase's get responses in the current 251 * metric setup. This helps avoid nested proto-files. This is primarily focused on track 2, 252 * where the provider uid is known. It ensures to run in a separate thread while emitting 253 * the multiple atoms to work with expected emit limits. 254 * 255 * @param providers a map with known providers and their held metric objects 256 * @param emitSequenceId an emitted sequence id for the current session, that matches the 257 * candidate emit value, as these metrics belong with the candidates 258 */ logApiCalledCandidateGetMetric(Map<String, ProviderSession> providers, int emitSequenceId)259 public static void logApiCalledCandidateGetMetric(Map<String, ProviderSession> providers, 260 int emitSequenceId) { 261 try { 262 // TODO(b/274954697) : To queue format in future optimizations (metrics POC support) 263 if (!LOG_FLAG) { 264 return; 265 } 266 var sessions = providers.values(); 267 for (var session : sessions) { 268 var metric = session.getProviderSessionMetric() 269 .getCandidatePhasePerProviderMetric(); 270 FrameworkStatsLog.write( 271 FrameworkStatsLog.CREDENTIAL_MANAGER_GET_REPORTED, 272 /* session_id */ metric.getSessionIdProvider(), 273 /* sequence_num */ emitSequenceId, 274 /* candidate_provider_uid */ metric.getCandidateUid(), 275 /* response_unique_classtypes */ 276 metric.getResponseCollective().getUniqueResponseStrings(), 277 /* per_classtype_counts */ 278 metric.getResponseCollective().getUniqueResponseCounts() 279 ); 280 } 281 } catch (Exception e) { 282 Slog.w(TAG, "Unexpected error during candidate get metric logging: " + e); 283 } 284 } 285 286 287 /** 288 * A logging utility used primarily for the candidate phase of the current metric setup. This 289 * will primarily focus on track 2, where the session id is associated with known providers, 290 * but NOT the calling app. 291 * 292 * @param providers a map with known providers and their held metric objects 293 * @param emitSequenceId an emitted sequence id for the current session 294 * @param initialPhaseMetric contains initial phase data to avoid repetition for candidate 295 * phase, track 2, logging 296 */ logApiCalledCandidatePhase(Map<String, ProviderSession> providers, int emitSequenceId, InitialPhaseMetric initialPhaseMetric)297 public static void logApiCalledCandidatePhase(Map<String, ProviderSession> providers, 298 int emitSequenceId, InitialPhaseMetric initialPhaseMetric) { 299 try { 300 if (!LOG_FLAG) { 301 return; 302 } 303 var providerSessions = providers.values(); 304 int providerSize = providerSessions.size(); 305 int sessionId = -1; 306 boolean queryReturned = false; 307 int[] candidateUidList = new int[providerSize]; 308 int[] candidateQueryStartTimeStampList = new int[providerSize]; 309 int[] candidateQueryEndTimeStampList = new int[providerSize]; 310 int[] candidateStatusList = new int[providerSize]; 311 boolean[] candidateHasExceptionList = new boolean[providerSize]; 312 int[] candidateTotalEntryCountList = new int[providerSize]; 313 int[] candidateCredentialEntryCountList = new int[providerSize]; 314 int[] candidateCredentialTypeCountList = new int[providerSize]; 315 int[] candidateActionEntryCountList = new int[providerSize]; 316 int[] candidateAuthEntryCountList = new int[providerSize]; 317 int[] candidateRemoteEntryCountList = new int[providerSize]; 318 String[] frameworkExceptionList = new String[providerSize]; 319 boolean[] candidatePrimaryProviderList = new boolean[providerSize]; 320 int index = 0; 321 for (var session : providerSessions) { 322 CandidatePhaseMetric metric = session.mProviderSessionMetric 323 .getCandidatePhasePerProviderMetric(); 324 if (sessionId == -1) { 325 sessionId = metric.getSessionIdProvider(); 326 } 327 if (!queryReturned) { 328 queryReturned = metric.isQueryReturned(); 329 } 330 candidateUidList[index] = metric.getCandidateUid(); 331 candidateQueryStartTimeStampList[index] = 332 metric.getTimestampFromReferenceStartMicroseconds( 333 metric.getStartQueryTimeNanoseconds()); 334 candidateQueryEndTimeStampList[index] = 335 metric.getTimestampFromReferenceStartMicroseconds( 336 metric.getQueryFinishTimeNanoseconds()); 337 candidateStatusList[index] = metric.getProviderQueryStatus(); 338 candidateHasExceptionList[index] = metric.isHasException(); 339 candidateTotalEntryCountList[index] = metric.getResponseCollective() 340 .getNumEntriesTotal(); 341 candidateCredentialEntryCountList[index] = metric.getResponseCollective() 342 .getCountForEntry(EntryEnum.CREDENTIAL_ENTRY); 343 candidateCredentialTypeCountList[index] = metric.getResponseCollective() 344 .getUniqueResponseStrings().length; 345 candidateActionEntryCountList[index] = metric.getResponseCollective() 346 .getCountForEntry(EntryEnum.ACTION_ENTRY); 347 candidateAuthEntryCountList[index] = metric.getResponseCollective() 348 .getCountForEntry(EntryEnum.AUTHENTICATION_ENTRY); 349 candidateRemoteEntryCountList[index] = metric.getResponseCollective() 350 .getCountForEntry(EntryEnum.REMOTE_ENTRY); 351 frameworkExceptionList[index] = metric.getFrameworkException(); 352 candidatePrimaryProviderList[index] = metric.isPrimary(); 353 index++; 354 } 355 FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED, 356 /* session_id */ sessionId, 357 /* sequence_num */ emitSequenceId, 358 /* query_returned */ queryReturned, 359 /* candidate_provider_uid_list */ candidateUidList, 360 /* candidate_provider_query_start_timestamp_microseconds */ 361 candidateQueryStartTimeStampList, 362 /* candidate_provider_query_end_timestamp_microseconds */ 363 candidateQueryEndTimeStampList, 364 /* candidate_provider_status */ candidateStatusList, 365 /* candidate_provider_has_exception */ candidateHasExceptionList, 366 /* candidate_provider_num_entries */ candidateTotalEntryCountList, 367 /* candidate_provider_action_entry_count */ candidateActionEntryCountList, 368 /* candidate_provider_credential_entry_count */ 369 candidateCredentialEntryCountList, 370 /* candidate_provider_credential_entry_type_count */ 371 candidateCredentialTypeCountList, 372 /* candidate_provider_remote_entry_count */ candidateRemoteEntryCountList, 373 /* candidate_provider_authentication_entry_count */ 374 candidateAuthEntryCountList, 375 /* framework_exception_per_provider */ 376 frameworkExceptionList, 377 /* origin_specified originSpecified */ 378 initialPhaseMetric.isOriginSpecified(), 379 /* request_unique_classtypes */ 380 initialPhaseMetric.getUniqueRequestStrings(), 381 /* per_classtype_counts */ 382 initialPhaseMetric.getUniqueRequestCounts(), 383 /* api_name */ 384 initialPhaseMetric.getApiName(), 385 /* primary_candidates_indicated */ 386 candidatePrimaryProviderList 387 ); 388 } catch (Exception e) { 389 Slog.w(TAG, "Unexpected error during candidate provider uid metric emit: " + e); 390 } 391 } 392 393 /** 394 * This is useful just to record an API calls' final event, and for no other purpose. 395 * 396 * @param apiName the api name to log 397 * @param apiStatus the status to log 398 * @param callingUid the calling uid 399 */ logApiCalledSimpleV2(ApiName apiName, ApiStatus apiStatus, int callingUid)400 public static void logApiCalledSimpleV2(ApiName apiName, ApiStatus apiStatus, 401 int callingUid) { 402 try { 403 if (!LOG_FLAG) { 404 return; 405 } 406 FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_APIV2_CALLED, 407 /* api_name */apiName.getMetricCode(), 408 /* caller_uid */ callingUid, 409 /* api_status */ apiStatus.getMetricCode()); 410 } catch (Exception e) { 411 Slog.w(TAG, "Unexpected error during simple v2 metric logging: " + e); 412 } 413 } 414 415 /** 416 * Handles the metric emit for the initial phase. 417 * 418 * @param initialPhaseMetric contains all the data for this emit 419 * @param sequenceNum the sequence number for this api call session emit 420 */ logApiCalledInitialPhase(InitialPhaseMetric initialPhaseMetric, int sequenceNum)421 public static void logApiCalledInitialPhase(InitialPhaseMetric initialPhaseMetric, 422 int sequenceNum) { 423 try { 424 if (!LOG_FLAG) { 425 return; 426 } 427 FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_INIT_PHASE_REPORTED, 428 /* api_name */ initialPhaseMetric.getApiName(), 429 /* caller_uid */ initialPhaseMetric.getCallerUid(), 430 /* session_id */ initialPhaseMetric.getSessionIdCaller(), 431 /* sequence_num */ sequenceNum, 432 /* initial_timestamp_reference_nanoseconds */ 433 initialPhaseMetric.getCredentialServiceStartedTimeNanoseconds(), 434 /* count_credential_request_classtypes */ 435 initialPhaseMetric.getCountRequestClassType(), 436 /* request_unique_classtypes */ 437 initialPhaseMetric.getUniqueRequestStrings(), 438 /* per_classtype_counts */ 439 initialPhaseMetric.getUniqueRequestCounts(), 440 /* origin_specified */ 441 initialPhaseMetric.isOriginSpecified(), 442 /* autofill_session_id */ 443 initialPhaseMetric.getAutofillSessionId(), 444 /* autofill_request_id */ 445 initialPhaseMetric.getAutofillRequestId() 446 ); 447 } catch (Exception e) { 448 Slog.w(TAG, "Unexpected error during initial metric emit: " + e); 449 } 450 } 451 452 /** 453 * A logging utility focused on track 1, where the calling app is known. This captures all 454 * aggregate information for the candidate phase. 455 * 456 * @param candidateAggregateMetric the aggregate candidate metric information collected 457 * @param sequenceNum the sequence number for this api call session emit 458 */ logApiCalledAggregateCandidate( CandidateAggregateMetric candidateAggregateMetric, int sequenceNum)459 public static void logApiCalledAggregateCandidate( 460 CandidateAggregateMetric candidateAggregateMetric, 461 int sequenceNum) { 462 try { 463 if (!LOG_FLAG) { 464 return; 465 } 466 FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_TOTAL_REPORTED, 467 /*session_id*/ candidateAggregateMetric.getSessionIdProvider(), 468 /*sequence_num*/ sequenceNum, 469 /*query_returned*/ candidateAggregateMetric.isQueryReturned(), 470 /*num_query_providers*/ candidateAggregateMetric.getNumProviders(), 471 /*min_query_start_timestamp_microseconds*/ 472 getMetricTimestampDifferenceMicroseconds( 473 candidateAggregateMetric.getMinProviderTimestampNanoseconds(), 474 candidateAggregateMetric.getServiceBeganTimeNanoseconds()), 475 /*max_query_end_timestamp_microseconds*/ 476 getMetricTimestampDifferenceMicroseconds( 477 candidateAggregateMetric.getMaxProviderTimestampNanoseconds(), 478 candidateAggregateMetric.getServiceBeganTimeNanoseconds()), 479 /*query_response_unique_classtypes*/ 480 candidateAggregateMetric.getAggregateCollectiveQuery() 481 .getUniqueResponseStrings(), 482 /*query_per_classtype_counts*/ 483 candidateAggregateMetric.getAggregateCollectiveQuery() 484 .getUniqueResponseCounts(), 485 /*query_unique_entries*/ 486 candidateAggregateMetric.getAggregateCollectiveQuery() 487 .getUniqueEntries(), 488 /*query_per_entry_counts*/ 489 candidateAggregateMetric.getAggregateCollectiveQuery() 490 .getUniqueEntryCounts(), 491 /*query_total_candidate_failure*/ 492 candidateAggregateMetric.getTotalQueryFailures(), 493 /*query_framework_exception_unique_classtypes*/ 494 candidateAggregateMetric.getUniqueExceptionStringsQuery(), 495 /*query_per_exception_classtype_counts*/ 496 candidateAggregateMetric.getUniqueExceptionCountsQuery(), 497 /*auth_response_unique_classtypes*/ 498 candidateAggregateMetric.getAggregateCollectiveAuth() 499 .getUniqueResponseStrings(), 500 /*auth_per_classtype_counts*/ 501 candidateAggregateMetric.getAggregateCollectiveAuth() 502 .getUniqueResponseCounts(), 503 /*auth_unique_entries*/ 504 candidateAggregateMetric.getAggregateCollectiveAuth() 505 .getUniqueEntries(), 506 /*auth_per_entry_counts*/ 507 candidateAggregateMetric.getAggregateCollectiveAuth() 508 .getUniqueEntryCounts(), 509 /*auth_total_candidate_failure*/ 510 candidateAggregateMetric.getTotalAuthFailures(), 511 /*auth_framework_exception_unique_classtypes*/ 512 candidateAggregateMetric.getUniqueExceptionStringsAuth(), 513 /*auth_per_exception_classtype_counts*/ 514 candidateAggregateMetric.getUniqueExceptionCountsAuth(), 515 /*num_auth_clicks*/ 516 candidateAggregateMetric.getNumAuthEntriesTapped(), 517 /*auth_returned*/ 518 candidateAggregateMetric.isAuthReturned() 519 ); 520 } catch (Exception e) { 521 Slog.w(TAG, "Unexpected error during total candidate metric logging: " + e); 522 } 523 } 524 525 /** 526 * A logging utility used primarily for the final phase of the current metric setup for track 1. 527 * 528 * @param finalPhaseMetric the coalesced data of the chosen provider 529 * @param browsingPhaseMetrics the coalesced data of the browsing phase 530 * @param apiStatus the final status of this particular api call 531 * @param emitSequenceId an emitted sequence id for the current session 532 */ logApiCalledNoUidFinal(ChosenProviderFinalPhaseMetric finalPhaseMetric, List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus, int emitSequenceId)533 public static void logApiCalledNoUidFinal(ChosenProviderFinalPhaseMetric finalPhaseMetric, 534 List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus, 535 int emitSequenceId) { 536 try { 537 if (!LOG_FLAG) { 538 return; 539 } 540 int browsedSize = browsingPhaseMetrics.size(); 541 int[] browsedClickedEntries = new int[browsedSize]; 542 int[] browsedProviderUid = new int[browsedSize]; 543 int index = 0; 544 for (CandidateBrowsingPhaseMetric metric : browsingPhaseMetrics) { 545 browsedClickedEntries[index] = metric.getEntryEnum(); 546 browsedProviderUid[index] = DEFAULT_INT_32; 547 index++; 548 } 549 FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_FINALNOUID_REPORTED, 550 /* session_id */ finalPhaseMetric.getSessionIdCaller(), 551 /* sequence_num */ emitSequenceId, 552 /* ui_returned_final_start */ finalPhaseMetric.isUiReturned(), 553 /* chosen_provider_query_start_timestamp_microseconds */ 554 finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric 555 .getQueryStartTimeNanoseconds()), 556 /* chosen_provider_query_end_timestamp_microseconds */ 557 finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric 558 .getQueryEndTimeNanoseconds()), 559 /* chosen_provider_ui_invoked_timestamp_microseconds */ 560 finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric 561 .getUiCallStartTimeNanoseconds()), 562 /* chosen_provider_ui_finished_timestamp_microseconds */ 563 finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric 564 .getUiCallEndTimeNanoseconds()), 565 /* chosen_provider_finished_timestamp_microseconds */ 566 finalPhaseMetric.getTimestampFromReferenceStartMicroseconds(finalPhaseMetric 567 .getFinalFinishTimeNanoseconds()), 568 /* chosen_provider_status */ finalPhaseMetric.getChosenProviderStatus(), 569 /* chosen_provider_has_exception */ finalPhaseMetric.isHasException(), 570 /* unique_entries */ 571 finalPhaseMetric.getResponseCollective().getUniqueEntries(), 572 /* per_entry_counts */ 573 finalPhaseMetric.getResponseCollective().getUniqueEntryCounts(), 574 /* unique_response_classtypes */ 575 finalPhaseMetric.getResponseCollective().getUniqueResponseStrings(), 576 /* per_classtype_counts */ 577 finalPhaseMetric.getResponseCollective().getUniqueResponseCounts(), 578 /* framework_exception_unique_classtype */ 579 finalPhaseMetric.getFrameworkException(), 580 /* clicked_entries */ browsedClickedEntries, 581 /* provider_of_clicked_entry */ browsedProviderUid, 582 /* api_status */ apiStatus, 583 /* primary_indicated */ finalPhaseMetric.isPrimary(), 584 /* oem_credential_manager_ui_uid */ finalPhaseMetric.getOemUiUid(), 585 /* fallback_credential_manager_ui_uid */ finalPhaseMetric.getFallbackUiUid(), 586 /* oem_ui_usage_status */ finalPhaseMetric.getOemUiUsageStatus() 587 ); 588 } catch (Exception e) { 589 Slog.w(TAG, "Unexpected error during final no uid metric logging: " + e); 590 } 591 } 592 593 } 594