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