1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.internal.util; 16 17 import static android.Manifest.permission.READ_DEVICE_CONFIG; 18 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 19 import static android.os.Trace.TRACE_TAG_APP; 20 import static android.provider.DeviceConfig.NAMESPACE_LATENCY_TRACKER; 21 22 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION; 23 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL; 24 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED; 25 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG; 26 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU; 27 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE; 28 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL; 29 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK; 30 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK; 31 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD; 32 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE; 33 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN; 34 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME; 35 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME; 36 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET; 37 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK; 38 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED; 39 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN; 40 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN; 41 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN; 42 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK; 43 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR; 44 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE; 45 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW; 46 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR; 47 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION; 48 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL; 49 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION; 50 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD; 51 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS; 52 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN; 53 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE; 54 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH; 55 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__UNKNOWN_ACTION; 56 import static com.android.internal.util.LatencyTracker.ActionProperties.ENABLE_SUFFIX; 57 import static com.android.internal.util.LatencyTracker.ActionProperties.LEGACY_TRACE_THRESHOLD_SUFFIX; 58 import static com.android.internal.util.LatencyTracker.ActionProperties.SAMPLE_INTERVAL_SUFFIX; 59 import static com.android.internal.util.LatencyTracker.ActionProperties.TRACE_THRESHOLD_SUFFIX; 60 61 import android.Manifest; 62 import android.annotation.ElapsedRealtimeLong; 63 import android.annotation.IntDef; 64 import android.annotation.NonNull; 65 import android.annotation.Nullable; 66 import android.annotation.RequiresPermission; 67 import android.app.ActivityThread; 68 import android.content.Context; 69 import android.os.Build; 70 import android.os.SystemClock; 71 import android.os.Trace; 72 import android.provider.DeviceConfig; 73 import android.text.TextUtils; 74 import android.util.EventLog; 75 import android.util.Log; 76 import android.util.SparseArray; 77 78 import com.android.internal.annotations.GuardedBy; 79 import com.android.internal.annotations.VisibleForTesting; 80 import com.android.internal.logging.EventLogTags; 81 import com.android.internal.os.BackgroundThread; 82 83 import java.lang.annotation.Retention; 84 import java.lang.annotation.RetentionPolicy; 85 import java.util.Locale; 86 import java.util.concurrent.ThreadLocalRandom; 87 import java.util.concurrent.TimeUnit; 88 89 /** 90 * Class to track various latencies in SystemUI. It then writes the latency to statsd and also 91 * outputs it to logcat so these latencies can be captured by tests and then used for dashboards. 92 * <p> 93 * This is currently only in Keyguard. It can be shared between SystemUI and Keyguard, but 94 * eventually we'd want to merge these two packages together so Keyguard can use common classes 95 * that are shared with SystemUI. 96 */ 97 public class LatencyTracker { 98 private static final String TAG = "LatencyTracker"; 99 public static final String SETTINGS_ENABLED_KEY = "enabled"; 100 private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; 101 private static final boolean DEBUG = false; 102 /** Default to being enabled on debug builds. */ 103 private static final boolean DEFAULT_ENABLED = Build.IS_DEBUGGABLE; 104 /** Default to collecting data for 1/5 of all actions (randomly sampled). */ 105 private static final int DEFAULT_SAMPLING_INTERVAL = 5; 106 107 /** 108 * Time it takes until the first frame of the notification panel to be displayed while expanding 109 */ 110 public static final int ACTION_EXPAND_PANEL = 0; 111 112 /** 113 * Time it takes until the first frame of recents is drawn after invoking it with the button. 114 */ 115 public static final int ACTION_TOGGLE_RECENTS = 1; 116 117 /** 118 * Time between we get a fingerprint acquired signal until we start with the unlock animation 119 */ 120 public static final int ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 2; 121 122 /** 123 * Time it takes to check PIN/Pattern/Password. 124 */ 125 public static final int ACTION_CHECK_CREDENTIAL = 3; 126 127 /** 128 * Time it takes to check fully PIN/Pattern/Password, i.e. that's the time spent including the 129 * actions to unlock a user. 130 */ 131 public static final int ACTION_CHECK_CREDENTIAL_UNLOCKED = 4; 132 133 /** 134 * Time it takes to turn on the screen. 135 */ 136 public static final int ACTION_TURN_ON_SCREEN = 5; 137 138 /** 139 * Time it takes to rotate the screen. 140 */ 141 public static final int ACTION_ROTATE_SCREEN = 6; 142 143 /* 144 * Time between we get a face acquired signal until we start with the unlock animation 145 */ 146 public static final int ACTION_FACE_WAKE_AND_UNLOCK = 7; 147 148 /** 149 * Time between the swipe-up gesture and window drawn of recents activity. 150 */ 151 public static final int ACTION_START_RECENTS_ANIMATION = 8; 152 153 /** 154 * Time it takes to for the camera based algorithm to rotate the screen. 155 */ 156 public static final int ACTION_ROTATE_SCREEN_CAMERA_CHECK = 9; 157 158 /** 159 * Time it takes the sensor to detect rotation. 160 */ 161 public static final int ACTION_ROTATE_SCREEN_SENSOR = 10; 162 163 /** 164 * Time it takes to start unlock animation . 165 */ 166 public static final int ACTION_LOCKSCREEN_UNLOCK = 11; 167 168 /** 169 * Time it takes to switch users. 170 */ 171 public static final int ACTION_USER_SWITCH = 12; 172 173 /** 174 * Time it takes to turn on the inner screen for a foldable device. 175 */ 176 public static final int ACTION_SWITCH_DISPLAY_UNFOLD = 13; 177 178 /** 179 * Time it takes for a UDFPS sensor to appear ready after it is touched. 180 */ 181 public static final int ACTION_UDFPS_ILLUMINATE = 14; 182 183 /** 184 * Time it takes for the gesture back affordance arrow to show up. 185 */ 186 public static final int ACTION_SHOW_BACK_ARROW = 15; 187 188 /** 189 * Time it takes for loading share sheet. 190 */ 191 public static final int ACTION_LOAD_SHARE_SHEET = 16; 192 193 /** 194 * Time it takes for showing the selection toolbar. 195 */ 196 public static final int ACTION_SHOW_SELECTION_TOOLBAR = 17; 197 198 /** 199 * Time it takes to show AOD display after folding the device. 200 */ 201 public static final int ACTION_FOLD_TO_AOD = 18; 202 203 /** 204 * Time it takes to show the {@link android.service.voice.VoiceInteractionSession} system UI 205 * after a {@link android.hardware.soundtrigger3.ISoundTriggerHw} voice trigger. 206 */ 207 public static final int ACTION_SHOW_VOICE_INTERACTION = 19; 208 209 /** 210 * Time it takes to request IME shown animation. 211 */ 212 public static final int ACTION_REQUEST_IME_SHOWN = 20; 213 214 /** 215 * Time it takes to request IME hidden animation. 216 */ 217 public static final int ACTION_REQUEST_IME_HIDDEN = 21; 218 219 /** 220 * Time it takes to load the animation frames in smart space doorbell card. 221 * It measures the duration from the images uris are passed into the view 222 * to all the frames are loaded. 223 * <p/> 224 * A long latency makes the doorbell animation looks janky until all the frames are loaded. 225 */ 226 public static final int ACTION_SMARTSPACE_DOORBELL = 22; 227 228 /** 229 * Time it takes to lazy-load the image of a {@link android.app.Notification.BigPictureStyle} 230 * notification. 231 */ 232 public static final int ACTION_NOTIFICATION_BIG_PICTURE_LOADED = 23; 233 234 /** 235 * Time it takes to unlock the device via fps, 236 * until either the launcher or the foreground app appears. 237 */ 238 public static final int ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME = 24; 239 240 /** 241 * Time it takes to start back preview surface animation after a back gesture starts. 242 */ 243 public static final int ACTION_BACK_SYSTEM_ANIMATION = 25; 244 245 /** 246 * Time notifications spent in hidden state for performance reasons. We might temporary 247 * hide notifications after display size changes (e.g. fold/unfold of a foldable device) 248 * and measure them while they are hidden to unblock rendering of the rest of the UI. 249 */ 250 public static final int ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE = 26; 251 252 /** 253 * The same as {@link ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE} but tracks time only 254 * when the notifications are hidden and when the shade is open or keyguard is visible. 255 */ 256 public static final int ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN = 27; 257 258 /** 259 * Time it takes to unlock the device via face, 260 * until either the launcher or the foreground app appears. 261 */ 262 public static final int ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME = 28; 263 264 /** 265 * Time it takes for the shade window to move display after a user interaction. 266 * <p> 267 * This starts when the user does an interaction that triggers the window reparenting, and 268 * finishes after the first doFrame done with the new display configuration. 269 */ 270 public static final int ACTION_SHADE_WINDOW_DISPLAY_CHANGE = 29; 271 272 /** 273 * Time it takes for the "enter desktop" mode animation to begin when initiated by dragging the 274 * app's handle into the desktop drop zone. 275 * <p> 276 * This measure the time from when the user releases their finger in the drop zone to when the 277 * animation for entering desktop mode visually begins. During this period, the home task and 278 * app headers for each window are initialized. Both have historically been expensive. See 279 * b/381396057 and b/360452034 respectively. 280 */ 281 public static final int ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG = 30; 282 283 /** 284 * Time it takes for the "enter desktop" mode animation to begin when initiated via the app 285 * handle's menu. 286 * <p> 287 * This measures the time from when the menu option is clicked/tapped to when the animation for 288 * entering desktop mode visually begins. During this period, the home task and app headers for 289 * each window are initialized. Both have historically been expensive. See b/381396057 and 290 * b/360452034 respectively. 291 */ 292 public static final int ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU = 31; 293 294 /** 295 * Time it takes for the "exit desktop" mode animation to begin after the user provides input. 296 * <p> 297 * Starts when the user provides input to exit desktop mode and enter full screen mode for an 298 * app. This including selecting the full screen button in an app handle's menu, dragging an 299 * app's window handle to the top of the screen, and using the appropriate keyboard shortcut. 300 * Ends when the animation to exit desktop mode begins. 301 */ 302 public static final int ACTION_DESKTOP_MODE_EXIT_MODE = 32; 303 304 private static final int[] ACTIONS_ALL = { 305 ACTION_EXPAND_PANEL, 306 ACTION_TOGGLE_RECENTS, 307 ACTION_FINGERPRINT_WAKE_AND_UNLOCK, 308 ACTION_CHECK_CREDENTIAL, 309 ACTION_CHECK_CREDENTIAL_UNLOCKED, 310 ACTION_TURN_ON_SCREEN, 311 ACTION_ROTATE_SCREEN, 312 ACTION_FACE_WAKE_AND_UNLOCK, 313 ACTION_START_RECENTS_ANIMATION, 314 ACTION_ROTATE_SCREEN_CAMERA_CHECK, 315 ACTION_ROTATE_SCREEN_SENSOR, 316 ACTION_LOCKSCREEN_UNLOCK, 317 ACTION_USER_SWITCH, 318 ACTION_SWITCH_DISPLAY_UNFOLD, 319 ACTION_UDFPS_ILLUMINATE, 320 ACTION_SHOW_BACK_ARROW, 321 ACTION_LOAD_SHARE_SHEET, 322 ACTION_SHOW_SELECTION_TOOLBAR, 323 ACTION_FOLD_TO_AOD, 324 ACTION_SHOW_VOICE_INTERACTION, 325 ACTION_REQUEST_IME_SHOWN, 326 ACTION_REQUEST_IME_HIDDEN, 327 ACTION_SMARTSPACE_DOORBELL, 328 ACTION_NOTIFICATION_BIG_PICTURE_LOADED, 329 ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME, 330 ACTION_BACK_SYSTEM_ANIMATION, 331 ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE, 332 ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, 333 ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, 334 ACTION_SHADE_WINDOW_DISPLAY_CHANGE, 335 ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG, 336 ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU, 337 ACTION_DESKTOP_MODE_EXIT_MODE, 338 }; 339 340 /** @hide */ 341 @IntDef({ 342 ACTION_EXPAND_PANEL, 343 ACTION_TOGGLE_RECENTS, 344 ACTION_FINGERPRINT_WAKE_AND_UNLOCK, 345 ACTION_CHECK_CREDENTIAL, 346 ACTION_CHECK_CREDENTIAL_UNLOCKED, 347 ACTION_TURN_ON_SCREEN, 348 ACTION_ROTATE_SCREEN, 349 ACTION_FACE_WAKE_AND_UNLOCK, 350 ACTION_START_RECENTS_ANIMATION, 351 ACTION_ROTATE_SCREEN_CAMERA_CHECK, 352 ACTION_ROTATE_SCREEN_SENSOR, 353 ACTION_LOCKSCREEN_UNLOCK, 354 ACTION_USER_SWITCH, 355 ACTION_SWITCH_DISPLAY_UNFOLD, 356 ACTION_UDFPS_ILLUMINATE, 357 ACTION_SHOW_BACK_ARROW, 358 ACTION_LOAD_SHARE_SHEET, 359 ACTION_SHOW_SELECTION_TOOLBAR, 360 ACTION_FOLD_TO_AOD, 361 ACTION_SHOW_VOICE_INTERACTION, 362 ACTION_REQUEST_IME_SHOWN, 363 ACTION_REQUEST_IME_HIDDEN, 364 ACTION_SMARTSPACE_DOORBELL, 365 ACTION_NOTIFICATION_BIG_PICTURE_LOADED, 366 ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME, 367 ACTION_BACK_SYSTEM_ANIMATION, 368 ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE, 369 ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, 370 ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, 371 ACTION_SHADE_WINDOW_DISPLAY_CHANGE, 372 ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG, 373 ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU, 374 ACTION_DESKTOP_MODE_EXIT_MODE, 375 }) 376 @Retention(RetentionPolicy.SOURCE) 377 public @interface Action {} 378 379 @VisibleForTesting 380 public static final int[] STATSD_ACTION = new int[] { 381 UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL, 382 UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS, 383 UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK, 384 UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL, 385 UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED, 386 UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN, 387 UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN, 388 UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK, 389 UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION, 390 UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK, 391 UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR, 392 UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK, 393 UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH, 394 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD, 395 UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE, 396 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW, 397 UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET, 398 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR, 399 UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD, 400 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION, 401 UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN, 402 UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN, 403 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL, 404 UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED, 405 UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME, 406 UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION, 407 UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE, 408 UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, 409 UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, 410 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE, 411 UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG, 412 UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU, 413 UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE, 414 }; 415 416 private final Object mLock = new Object(); 417 @GuardedBy("mLock") 418 private final SparseArray<Session> mSessions = new SparseArray<>(); 419 @GuardedBy("mLock") 420 private final SparseArray<ActionProperties> mActionPropertiesMap = new SparseArray<>(); 421 @GuardedBy("mLock") 422 private boolean mEnabled; 423 private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = 424 this::updateProperties; 425 426 // Wrapping this in a holder class achieves lazy loading behavior 427 private static final class SLatencyTrackerHolder { 428 private static final LatencyTracker sLatencyTracker; 429 430 static { 431 sLatencyTracker = new LatencyTracker(); sLatencyTracker.startListeningForLatencyTrackerConfigChanges()432 sLatencyTracker.startListeningForLatencyTrackerConfigChanges(); 433 } 434 } 435 getInstance(Context context)436 public static LatencyTracker getInstance(Context context) { 437 return SLatencyTrackerHolder.sLatencyTracker; 438 } 439 440 /** 441 * Constructor for LatencyTracker 442 * 443 * <p>This constructor is only visible for test classes to inject their own consumer callbacks 444 * 445 * @param startListeningForPropertyChanges If set, constructor will register for device config 446 * property updates prior to returning. If not set, 447 * {@link #startListeningForLatencyTrackerConfigChanges} must be called 448 * to start listening. 449 */ 450 @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) 451 @VisibleForTesting LatencyTracker()452 public LatencyTracker() { 453 mEnabled = DEFAULT_ENABLED; 454 } 455 updateProperties(DeviceConfig.Properties properties)456 private void updateProperties(DeviceConfig.Properties properties) { 457 synchronized (mLock) { 458 int samplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, 459 DEFAULT_SAMPLING_INTERVAL); 460 boolean wasEnabled = mEnabled; 461 mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED); 462 if (wasEnabled != mEnabled) { 463 Log.d(TAG, "Latency tracker " + (mEnabled ? "enabled" : "disabled") + "."); 464 } 465 for (int action : ACTIONS_ALL) { 466 String actionName = getNameOfAction(STATSD_ACTION[action]).toLowerCase(Locale.ROOT); 467 int legacyActionTraceThreshold = properties.getInt( 468 actionName + LEGACY_TRACE_THRESHOLD_SUFFIX, -1); 469 mActionPropertiesMap.put(action, new ActionProperties(action, 470 properties.getBoolean(actionName + ENABLE_SUFFIX, mEnabled), 471 properties.getInt(actionName + SAMPLE_INTERVAL_SUFFIX, samplingInterval), 472 properties.getInt(actionName + TRACE_THRESHOLD_SUFFIX, 473 legacyActionTraceThreshold))); 474 } 475 onDeviceConfigPropertiesUpdated(mActionPropertiesMap); 476 } 477 } 478 479 /** 480 * Test method to start listening to {@link DeviceConfig} properties changes. 481 * 482 * <p>During testing, a {@link LatencyTracker} it is desired to stop and start listening for 483 * config updates. 484 * 485 * <p>This is not used for production usages of this class outside of testing as we are 486 * using a single static object. 487 */ 488 @VisibleForTesting 489 @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) startListeningForLatencyTrackerConfigChanges()490 public void startListeningForLatencyTrackerConfigChanges() { 491 final Context context = ActivityThread.currentApplication(); 492 if (context == null) { 493 Log.e( 494 TAG, 495 String.format( 496 "No application for package: %s. Latency Tracker Disabled", 497 ActivityThread.currentPackageName())); 498 return; 499 } 500 if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) != PERMISSION_GRANTED) { 501 if (DEBUG) { 502 synchronized (mLock) { 503 Log.d(TAG, "Initialized the LatencyTracker." 504 + " (No READ_DEVICE_CONFIG permission to change configs)" 505 + " enabled=" + mEnabled + ", package=" + context.getPackageName()); 506 } 507 } 508 return; 509 } 510 511 // Post initialization to the background in case we're running on the main thread. 512 BackgroundThread.getHandler().post(() -> { 513 try { 514 this.updateProperties( 515 DeviceConfig.getProperties(NAMESPACE_LATENCY_TRACKER)); 516 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_LATENCY_TRACKER, 517 BackgroundThread.getExecutor(), mOnPropertiesChangedListener); 518 } catch (SecurityException ex) { 519 // In case of running tests that the main thread passes the check, 520 // but the background thread doesn't have necessary permissions. 521 // Swallow it since it's ok to ignore device config changes in the tests. 522 Log.d(TAG, "Can't get properties: READ_DEVICE_CONFIG granted=" 523 + context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) 524 + ", package=" + context.getPackageName()); 525 } 526 }); 527 } 528 529 /** 530 * Test method to stop listening to {@link DeviceConfig} properties changes. 531 * 532 * <p>During testing, a {@link LatencyTracker} it is desired to stop and start listening for 533 * config updates. 534 * 535 * <p>This is not used for production usages of this class outside of testing as we are 536 * using a single static object. 537 */ 538 @VisibleForTesting stopListeningForLatencyTrackerConfigChanges()539 public void stopListeningForLatencyTrackerConfigChanges() { 540 DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener); 541 } 542 543 /** 544 * A helper method to translate action type to name. 545 * 546 * @param atomsProtoAction the action type defined in AtomsProto.java 547 * @return the name of the action 548 */ getNameOfAction(int atomsProtoAction)549 public static String getNameOfAction(int atomsProtoAction) { 550 // Defined in AtomsProto.java 551 switch (atomsProtoAction) { 552 case UIACTION_LATENCY_REPORTED__ACTION__UNKNOWN_ACTION: 553 return "UNKNOWN"; 554 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL: 555 return "ACTION_EXPAND_PANEL"; 556 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS: 557 return "ACTION_TOGGLE_RECENTS"; 558 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK: 559 return "ACTION_FINGERPRINT_WAKE_AND_UNLOCK"; 560 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL: 561 return "ACTION_CHECK_CREDENTIAL"; 562 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED: 563 return "ACTION_CHECK_CREDENTIAL_UNLOCKED"; 564 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN: 565 return "ACTION_TURN_ON_SCREEN"; 566 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN: 567 return "ACTION_ROTATE_SCREEN"; 568 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK: 569 return "ACTION_FACE_WAKE_AND_UNLOCK"; 570 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION: 571 return "ACTION_START_RECENTS_ANIMATION"; 572 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK: 573 return "ACTION_ROTATE_SCREEN_CAMERA_CHECK"; 574 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR: 575 return "ACTION_ROTATE_SCREEN_SENSOR"; 576 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK: 577 return "ACTION_LOCKSCREEN_UNLOCK"; 578 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH: 579 return "ACTION_USER_SWITCH"; 580 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD: 581 return "ACTION_SWITCH_DISPLAY_UNFOLD"; 582 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE: 583 return "ACTION_UDFPS_ILLUMINATE"; 584 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW: 585 return "ACTION_SHOW_BACK_ARROW"; 586 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET: 587 return "ACTION_LOAD_SHARE_SHEET"; 588 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR: 589 return "ACTION_SHOW_SELECTION_TOOLBAR"; 590 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD: 591 return "ACTION_FOLD_TO_AOD"; 592 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION: 593 return "ACTION_SHOW_VOICE_INTERACTION"; 594 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN: 595 return "ACTION_REQUEST_IME_SHOWN"; 596 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN: 597 return "ACTION_REQUEST_IME_HIDDEN"; 598 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL: 599 return "ACTION_SMARTSPACE_DOORBELL"; 600 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED: 601 return "ACTION_NOTIFICATION_BIG_PICTURE_LOADED"; 602 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME: 603 return "ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME"; 604 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION: 605 return "ACTION_BACK_SYSTEM_ANIMATION"; 606 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE: 607 return "ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE"; 608 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN: 609 return "ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN"; 610 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME: 611 return "ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME"; 612 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE: 613 return "ACTION_SHADE_WINDOW_DISPLAY_CHANGE"; 614 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG: 615 return "ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG"; 616 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU: 617 return "ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU"; 618 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE: 619 return "ACTION_DESKTOP_MODE_EXIT_MODE"; 620 default: 621 throw new IllegalArgumentException("Invalid action"); 622 } 623 } 624 getTraceNameOfAction(@ction int action, String tag)625 private static String getTraceNameOfAction(@Action int action, String tag) { 626 if (TextUtils.isEmpty(tag)) { 627 return "L<" + getNameOfAction(STATSD_ACTION[action]) + ">"; 628 } else { 629 return "L<" + getNameOfAction(STATSD_ACTION[action]) + "::" + tag + ">"; 630 } 631 } 632 getTraceTriggerNameForAction(@ction int action)633 private static String getTraceTriggerNameForAction(@Action int action) { 634 return "com.android.telemetry.latency-tracker-" + getNameOfAction(STATSD_ACTION[action]); 635 } 636 637 /** 638 * @deprecated Use {@link #isEnabled(Context, int)} 639 */ 640 @Deprecated isEnabled(Context ctx)641 public static boolean isEnabled(Context ctx) { 642 return getInstance(ctx).isEnabled(); 643 } 644 645 /** 646 * @deprecated Used {@link #isEnabled(int)} 647 */ 648 @Deprecated isEnabled()649 public boolean isEnabled() { 650 synchronized (mLock) { 651 return mEnabled; 652 } 653 } 654 isEnabled(Context ctx, int action)655 public static boolean isEnabled(Context ctx, int action) { 656 return getInstance(ctx).isEnabled(action); 657 } 658 isEnabled(int action)659 public boolean isEnabled(int action) { 660 synchronized (mLock) { 661 ActionProperties actionProperties = mActionPropertiesMap.get(action); 662 if (actionProperties != null) { 663 return actionProperties.isEnabled(); 664 } 665 return false; 666 } 667 } 668 669 /** 670 * Notifies that an action is starting. <s>This needs to be called from the main thread.</s> 671 * 672 * @param action The action to start. One of the ACTION_* values. 673 */ onActionStart(@ction int action)674 public void onActionStart(@Action int action) { 675 onActionStart(action, null); 676 } 677 678 /** 679 * Notifies that an action is starting. <s>This needs to be called from the main thread.</s> 680 * 681 * @param action The action to start. One of the ACTION_* values. 682 * @param tag The brief description of the action. 683 */ onActionStart(@ction int action, String tag)684 public void onActionStart(@Action int action, String tag) { 685 synchronized (mLock) { 686 if (!isEnabled(action)) { 687 return; 688 } 689 // skip if the action is already instrumenting. 690 if (mSessions.get(action) != null) { 691 return; 692 } 693 Session session = new Session(action, tag); 694 session.begin(() -> onActionCancel(action)); 695 mSessions.put(action, session); 696 697 if (DEBUG) { 698 Log.d(TAG, "onActionStart: " + session.name() + ", start=" + session.mStartRtc); 699 } 700 } 701 } 702 703 /** 704 * Notifies that an action has ended. <s>This needs to be called from the main thread.</s> 705 * 706 * @param action The action to end. One of the ACTION_* values. 707 */ onActionEnd(@ction int action)708 public void onActionEnd(@Action int action) { 709 synchronized (mLock) { 710 if (!isEnabled(action)) { 711 return; 712 } 713 Session session = mSessions.get(action); 714 if (session == null) { 715 return; 716 } 717 session.end(); 718 mSessions.delete(action); 719 logAction(action, session.duration()); 720 721 if (DEBUG) { 722 Log.d(TAG, "onActionEnd:" + session.name() + ", duration=" + session.duration()); 723 } 724 } 725 } 726 727 /** 728 * Notifies that an action has canceled. <s>This needs to be called from the main thread.</s> 729 * 730 * @param action The action to cancel. One of the ACTION_* values. 731 * @hide 732 */ onActionCancel(@ction int action)733 public void onActionCancel(@Action int action) { 734 synchronized (mLock) { 735 Session session = mSessions.get(action); 736 if (session == null) { 737 return; 738 } 739 session.cancel(); 740 mSessions.delete(action); 741 742 if (DEBUG) { 743 Log.d(TAG, "onActionCancel: " + session.name()); 744 } 745 } 746 } 747 748 /** 749 * Testing API to get the time when a given action was started. 750 * 751 * @param action Action which to retrieve start time from 752 * @return Elapsed realtime timestamp when the action started. -1 if the action is not active. 753 * @hide 754 */ 755 @VisibleForTesting 756 @ElapsedRealtimeLong getActiveActionStartTime(@ction int action)757 public long getActiveActionStartTime(@Action int action) { 758 synchronized (mLock) { 759 if (mSessions.contains(action)) { 760 return mSessions.get(action).mStartRtc; 761 } 762 return -1; 763 } 764 } 765 766 /** 767 * Logs an action that has started and ended. This needs to be called from the main thread. 768 * 769 * @param action The action to end. One of the ACTION_* values. 770 * @param duration The duration of the action in ms. 771 */ logAction(@ction int action, int duration)772 public void logAction(@Action int action, int duration) { 773 boolean shouldSample; 774 int traceThreshold; 775 synchronized (mLock) { 776 if (!isEnabled(action)) { 777 return; 778 } 779 ActionProperties actionProperties = mActionPropertiesMap.get(action); 780 if (actionProperties == null) { 781 return; 782 } 783 int nextRandNum = ThreadLocalRandom.current().nextInt( 784 actionProperties.getSamplingInterval()); 785 shouldSample = nextRandNum == 0; 786 traceThreshold = actionProperties.getTraceThreshold(); 787 } 788 789 boolean shouldTriggerPerfettoTrace = traceThreshold > 0 && duration >= traceThreshold; 790 791 if (DEBUG) { 792 Log.i(TAG, "logAction: " + getNameOfAction(STATSD_ACTION[action]) 793 + " duration=" + duration 794 + " shouldSample=" + shouldSample 795 + " shouldTriggerPerfettoTrace=" + shouldTriggerPerfettoTrace); 796 } 797 798 EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration); 799 if (shouldTriggerPerfettoTrace) { 800 onTriggerPerfetto(getTraceTriggerNameForAction(action)); 801 } 802 if (shouldSample) { 803 onLogToFrameworkStats( 804 new FrameworkStatsLogEvent(action, FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED, 805 STATSD_ACTION[action], duration) 806 ); 807 } 808 } 809 810 static class Session { 811 @Action 812 private final int mAction; 813 private final String mTag; 814 private final String mName; 815 private Runnable mTimeoutRunnable; 816 private long mStartRtc = -1; 817 private long mEndRtc = -1; 818 Session(@ction int action, @Nullable String tag)819 Session(@Action int action, @Nullable String tag) { 820 mAction = action; 821 mTag = tag; 822 mName = TextUtils.isEmpty(mTag) 823 ? getNameOfAction(STATSD_ACTION[mAction]) 824 : getNameOfAction(STATSD_ACTION[mAction]) + "::" + mTag; 825 } 826 name()827 String name() { 828 return mName; 829 } 830 traceName()831 String traceName() { 832 return getTraceNameOfAction(mAction, mTag); 833 } 834 begin(@onNull Runnable timeoutAction)835 void begin(@NonNull Runnable timeoutAction) { 836 mStartRtc = SystemClock.elapsedRealtime(); 837 Trace.asyncTraceForTrackBegin(TRACE_TAG_APP, traceName(), traceName(), 0); 838 839 // start counting timeout. 840 mTimeoutRunnable = () -> { 841 Trace.instantForTrack(TRACE_TAG_APP, traceName(), "timeout"); 842 timeoutAction.run(); 843 }; 844 BackgroundThread.getHandler() 845 .postDelayed(mTimeoutRunnable, TimeUnit.SECONDS.toMillis(15)); 846 } 847 end()848 void end() { 849 mEndRtc = SystemClock.elapsedRealtime(); 850 Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), 0); 851 BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); 852 mTimeoutRunnable = null; 853 } 854 cancel()855 void cancel() { 856 Trace.instantForTrack(TRACE_TAG_APP, traceName(), "cancel"); 857 Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), 0); 858 BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); 859 mTimeoutRunnable = null; 860 } 861 duration()862 int duration() { 863 return (int) (mEndRtc - mStartRtc); 864 } 865 } 866 867 @VisibleForTesting 868 public static class ActionProperties { 869 static final String ENABLE_SUFFIX = "_enable"; 870 static final String SAMPLE_INTERVAL_SUFFIX = "_sample_interval"; 871 // TODO: migrate all usages of the legacy trace threshold property 872 static final String LEGACY_TRACE_THRESHOLD_SUFFIX = ""; 873 static final String TRACE_THRESHOLD_SUFFIX = "_trace_threshold"; 874 875 @Action 876 private final int mAction; 877 private final boolean mEnabled; 878 private final int mSamplingInterval; 879 private final int mTraceThreshold; 880 881 @VisibleForTesting ActionProperties( @ction int action, boolean enabled, int samplingInterval, int traceThreshold)882 public ActionProperties( 883 @Action int action, 884 boolean enabled, 885 int samplingInterval, 886 int traceThreshold) { 887 this.mAction = action; 888 com.android.internal.util.AnnotationValidations.validate( 889 Action.class, null, mAction); 890 this.mEnabled = enabled; 891 this.mSamplingInterval = samplingInterval; 892 this.mTraceThreshold = traceThreshold; 893 } 894 895 @VisibleForTesting 896 @Action getAction()897 public int getAction() { 898 return mAction; 899 } 900 901 @VisibleForTesting isEnabled()902 public boolean isEnabled() { 903 return mEnabled; 904 } 905 906 @VisibleForTesting getSamplingInterval()907 public int getSamplingInterval() { 908 return mSamplingInterval; 909 } 910 911 @VisibleForTesting getTraceThreshold()912 public int getTraceThreshold() { 913 return mTraceThreshold; 914 } 915 916 @Override toString()917 public String toString() { 918 return "ActionProperties{" 919 + " mAction=" + mAction 920 + ", mEnabled=" + mEnabled 921 + ", mSamplingInterval=" + mSamplingInterval 922 + ", mTraceThreshold=" + mTraceThreshold 923 + "}"; 924 } 925 926 @Override equals(@ullable Object o)927 public boolean equals(@Nullable Object o) { 928 if (this == o) { 929 return true; 930 } 931 if (o == null) { 932 return false; 933 } 934 if (!(o instanceof ActionProperties)) { 935 return false; 936 } 937 ActionProperties that = (ActionProperties) o; 938 return mAction == that.mAction 939 && mEnabled == that.mEnabled 940 && mSamplingInterval == that.mSamplingInterval 941 && mTraceThreshold == that.mTraceThreshold; 942 } 943 944 @Override hashCode()945 public int hashCode() { 946 int _hash = 1; 947 _hash = 31 * _hash + mAction; 948 _hash = 31 * _hash + Boolean.hashCode(mEnabled); 949 _hash = 31 * _hash + mSamplingInterval; 950 _hash = 31 * _hash + mTraceThreshold; 951 return _hash; 952 } 953 } 954 955 /** 956 * Testing method intended to be overridden to determine when the LatencyTracker's device 957 * properties are updated. 958 */ 959 @VisibleForTesting onDeviceConfigPropertiesUpdated(SparseArray<ActionProperties> actionProperties)960 public void onDeviceConfigPropertiesUpdated(SparseArray<ActionProperties> actionProperties) { 961 if (DEBUG) { 962 Log.d(TAG, "onDeviceConfigPropertiesUpdated: " + actionProperties); 963 } 964 } 965 966 /** 967 * Testing class intended to be overridden to determine when LatencyTracker triggers perfetto. 968 */ 969 @VisibleForTesting onTriggerPerfetto(String triggerName)970 public void onTriggerPerfetto(String triggerName) { 971 if (DEBUG) { 972 Log.i(TAG, "onTriggerPerfetto: triggerName=" + triggerName); 973 } 974 PerfettoTrigger.trigger(triggerName); 975 } 976 977 /** 978 * Testing method intended to be overridden to determine when LatencyTracker writes to 979 * FrameworkStatsLog. 980 */ 981 @VisibleForTesting onLogToFrameworkStats(FrameworkStatsLogEvent event)982 public void onLogToFrameworkStats(FrameworkStatsLogEvent event) { 983 if (DEBUG) { 984 Log.i(TAG, "onLogToFrameworkStats: event=" + event); 985 } 986 FrameworkStatsLog.write(event.logCode, event.statsdAction, event.durationMillis); 987 } 988 989 /** 990 * Testing class intended to reject what should be written to the {@link FrameworkStatsLog} 991 * 992 * <p>This class is used in {@link #onLogToFrameworkStats(FrameworkStatsLogEvent)} for test code 993 * to observer when and what information is being logged by {@link LatencyTracker} 994 */ 995 @VisibleForTesting 996 public static class FrameworkStatsLogEvent { 997 998 @VisibleForTesting 999 public final int action; 1000 @VisibleForTesting 1001 public final int logCode; 1002 @VisibleForTesting 1003 public final int statsdAction; 1004 @VisibleForTesting 1005 public final int durationMillis; 1006 FrameworkStatsLogEvent(int action, int logCode, int statsdAction, int durationMillis)1007 private FrameworkStatsLogEvent(int action, int logCode, int statsdAction, 1008 int durationMillis) { 1009 this.action = action; 1010 this.logCode = logCode; 1011 this.statsdAction = statsdAction; 1012 this.durationMillis = durationMillis; 1013 } 1014 1015 @Override toString()1016 public String toString() { 1017 return "FrameworkStatsLogEvent{" 1018 + " logCode=" + logCode 1019 + ", statsdAction=" + statsdAction 1020 + ", durationMillis=" + durationMillis 1021 + "}"; 1022 } 1023 } 1024 } 1025