1 /* 2 * Copyright (C) 2020 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.internal.jank; 18 19 import static android.Manifest.permission.READ_DEVICE_CONFIG; 20 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 21 import static android.provider.DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR; 22 23 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL; 24 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT; 25 import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL; 26 import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN; 27 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION; 28 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION; 29 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_SHOW_ANIMATION; 30 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL; 31 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME; 32 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK; 33 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP; 34 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON; 35 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS; 36 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_WIDGET; 37 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS; 38 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE; 39 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME; 40 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS; 41 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_SEARCH_RESULT; 42 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH; 43 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNLOCK_ENTRANCE_ANIMATION; 44 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION; 45 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA; 46 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_OCCLUSION; 47 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR; 48 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_DISAPPEAR; 49 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PATTERN_APPEAR; 50 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PATTERN_DISAPPEAR; 51 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PIN_APPEAR; 52 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PIN_DISAPPEAR; 53 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_FROM_AOD; 54 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD; 55 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION; 56 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE; 57 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_ENTER_TRANSITION; 58 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_EXIT_TRANSITION; 59 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION; 60 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__RECENTS_SCROLLING; 61 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF; 62 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD; 63 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL; 64 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER; 65 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE; 66 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH; 67 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON; 68 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER; 69 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE; 70 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON; 71 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_CLEAR_ALL; 72 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_DIALOG_OPEN; 73 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR; 74 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR; 75 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR; 76 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD; 77 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_REMOVE; 78 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_EXPAND_COLLAPSE; 79 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_SCROLL_SWIPE; 80 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_EXPAND; 81 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE; 82 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING; 83 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD; 84 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM; 85 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_DOUBLE_TAP_DIVIDER; 86 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_ENTER; 87 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_EXIT; 88 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_RESIZE; 89 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP; 90 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_SCREEN_FOR_STATUS; 91 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_NEXT_FLOW; 92 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS; 93 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS; 94 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT; 95 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TASKBAR_COLLAPSE; 96 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TASKBAR_EXPAND; 97 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM; 98 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_DIALOG_OPEN; 99 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH; 100 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL; 101 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION; 102 103 import android.Manifest; 104 import android.annotation.ColorInt; 105 import android.annotation.IntDef; 106 import android.annotation.NonNull; 107 import android.annotation.RequiresPermission; 108 import android.annotation.UiThread; 109 import android.annotation.WorkerThread; 110 import android.app.ActivityThread; 111 import android.content.Context; 112 import android.graphics.Color; 113 import android.os.Build; 114 import android.os.Handler; 115 import android.os.HandlerExecutor; 116 import android.os.HandlerThread; 117 import android.os.SystemClock; 118 import android.provider.DeviceConfig; 119 import android.text.TextUtils; 120 import android.util.Log; 121 import android.util.SparseArray; 122 import android.view.Choreographer; 123 import android.view.SurfaceControl; 124 import android.view.View; 125 126 import com.android.internal.annotations.GuardedBy; 127 import com.android.internal.annotations.VisibleForTesting; 128 import com.android.internal.jank.FrameTracker.ChoreographerWrapper; 129 import com.android.internal.jank.FrameTracker.FrameMetricsWrapper; 130 import com.android.internal.jank.FrameTracker.FrameTrackerListener; 131 import com.android.internal.jank.FrameTracker.Reasons; 132 import com.android.internal.jank.FrameTracker.SurfaceControlWrapper; 133 import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper; 134 import com.android.internal.jank.FrameTracker.ViewRootWrapper; 135 import com.android.internal.util.PerfettoTrigger; 136 137 import java.lang.annotation.Retention; 138 import java.lang.annotation.RetentionPolicy; 139 import java.time.Instant; 140 import java.util.Locale; 141 import java.util.concurrent.ThreadLocalRandom; 142 import java.util.concurrent.TimeUnit; 143 144 /** 145 * This class let users to begin and end the always on tracing mechanism. 146 * 147 * Enabling for local development: 148 * 149 * adb shell device_config put interaction_jank_monitor enabled true 150 * adb shell device_config put interaction_jank_monitor sampling_interval 1 151 * 152 * On debuggable builds, an overlay can be used to display the name of the 153 * currently running cuj using: 154 * 155 * adb shell device_config put interaction_jank_monitor debug_overlay_enabled true 156 * 157 * NOTE: The overlay will interfere with metrics, so it should only be used 158 * for understanding which UI events correspeond to which CUJs. 159 * 160 * @hide 161 */ 162 public class InteractionJankMonitor { 163 private static final String TAG = InteractionJankMonitor.class.getSimpleName(); 164 private static final boolean DEBUG = false; 165 private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName(); 166 167 private static final String DEFAULT_WORKER_NAME = TAG + "-Worker"; 168 private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L); 169 static final long EXECUTOR_TASK_TIMEOUT = 500; 170 private static final String SETTINGS_ENABLED_KEY = "enabled"; 171 private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; 172 private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY = 173 "trace_threshold_missed_frames"; 174 private static final String SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY = 175 "trace_threshold_frame_time_millis"; 176 private static final String SETTINGS_DEBUG_OVERLAY_ENABLED_KEY = "debug_overlay_enabled"; 177 /** Default to being enabled on debug builds. */ 178 private static final boolean DEFAULT_ENABLED = Build.IS_DEBUGGABLE; 179 /** Default to collecting data for all CUJs. */ 180 private static final int DEFAULT_SAMPLING_INTERVAL = 1; 181 /** Default to triggering trace if 3 frames are missed OR a frame takes at least 64ms */ 182 private static final int DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES = 3; 183 private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64; 184 private static final boolean DEFAULT_DEBUG_OVERLAY_ENABLED = false; 185 186 @VisibleForTesting 187 public static final int MAX_LENGTH_OF_CUJ_NAME = 80; 188 private static final int MAX_LENGTH_SESSION_NAME = 100; 189 190 public static final String ACTION_SESSION_END = ACTION_PREFIX + ".ACTION_SESSION_END"; 191 public static final String ACTION_SESSION_CANCEL = ACTION_PREFIX + ".ACTION_SESSION_CANCEL"; 192 193 // Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE. 194 public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 0; 195 public static final int CUJ_NOTIFICATION_SHADE_SCROLL_FLING = 2; 196 public static final int CUJ_NOTIFICATION_SHADE_ROW_EXPAND = 3; 197 public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = 4; 198 public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = 5; 199 public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = 6; 200 public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS = 7; 201 public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON = 8; 202 public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = 9; 203 public static final int CUJ_LAUNCHER_APP_CLOSE_TO_PIP = 10; 204 public static final int CUJ_LAUNCHER_QUICK_SWITCH = 11; 205 public static final int CUJ_NOTIFICATION_HEADS_UP_APPEAR = 12; 206 public static final int CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR = 13; 207 public static final int CUJ_NOTIFICATION_ADD = 14; 208 public static final int CUJ_NOTIFICATION_REMOVE = 15; 209 public static final int CUJ_NOTIFICATION_APP_START = 16; 210 public static final int CUJ_LOCKSCREEN_PASSWORD_APPEAR = 17; 211 public static final int CUJ_LOCKSCREEN_PATTERN_APPEAR = 18; 212 public static final int CUJ_LOCKSCREEN_PIN_APPEAR = 19; 213 public static final int CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR = 20; 214 public static final int CUJ_LOCKSCREEN_PATTERN_DISAPPEAR = 21; 215 public static final int CUJ_LOCKSCREEN_PIN_DISAPPEAR = 22; 216 public static final int CUJ_LOCKSCREEN_TRANSITION_FROM_AOD = 23; 217 public static final int CUJ_LOCKSCREEN_TRANSITION_TO_AOD = 24; 218 public static final int CUJ_LAUNCHER_OPEN_ALL_APPS = 25; 219 public static final int CUJ_LAUNCHER_ALL_APPS_SCROLL = 26; 220 public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET = 27; 221 public static final int CUJ_SETTINGS_PAGE_SCROLL = 28; 222 public static final int CUJ_LOCKSCREEN_UNLOCK_ANIMATION = 29; 223 public static final int CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON = 30; 224 public static final int CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER = 31; 225 public static final int CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE = 32; 226 public static final int CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON = 33; 227 public static final int CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP = 34; 228 public static final int CUJ_PIP_TRANSITION = 35; 229 public static final int CUJ_WALLPAPER_TRANSITION = 36; 230 public static final int CUJ_USER_SWITCH = 37; 231 public static final int CUJ_SPLASHSCREEN_AVD = 38; 232 public static final int CUJ_SPLASHSCREEN_EXIT_ANIM = 39; 233 public static final int CUJ_SCREEN_OFF = 40; 234 public static final int CUJ_SCREEN_OFF_SHOW_AOD = 41; 235 public static final int CUJ_ONE_HANDED_ENTER_TRANSITION = 42; 236 public static final int CUJ_ONE_HANDED_EXIT_TRANSITION = 43; 237 public static final int CUJ_UNFOLD_ANIM = 44; 238 public static final int CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS = 45; 239 public static final int CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS = 46; 240 public static final int CUJ_SUW_LOADING_TO_NEXT_FLOW = 47; 241 public static final int CUJ_SUW_LOADING_SCREEN_FOR_STATUS = 48; 242 public static final int CUJ_SPLIT_SCREEN_ENTER = 49; 243 public static final int CUJ_SPLIT_SCREEN_EXIT = 50; 244 public static final int CUJ_LOCKSCREEN_LAUNCH_CAMERA = 51; // reserved. 245 public static final int CUJ_SPLIT_SCREEN_RESIZE = 52; 246 public static final int CUJ_SETTINGS_SLIDER = 53; 247 public static final int CUJ_TAKE_SCREENSHOT = 54; 248 public static final int CUJ_VOLUME_CONTROL = 55; 249 public static final int CUJ_BIOMETRIC_PROMPT_TRANSITION = 56; 250 public static final int CUJ_SETTINGS_TOGGLE = 57; 251 public static final int CUJ_SHADE_DIALOG_OPEN = 58; 252 public static final int CUJ_USER_DIALOG_OPEN = 59; 253 public static final int CUJ_TASKBAR_EXPAND = 60; 254 public static final int CUJ_TASKBAR_COLLAPSE = 61; 255 public static final int CUJ_SHADE_CLEAR_ALL = 62; 256 public static final int CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION = 63; 257 public static final int CUJ_LOCKSCREEN_OCCLUSION = 64; 258 public static final int CUJ_RECENTS_SCROLLING = 65; 259 public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66; 260 public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67; 261 public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68; 262 public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70; 263 public static final int CUJ_LAUNCHER_OPEN_SEARCH_RESULT = 71; 264 // 72 - 77 are reserved for b/281564325. 265 266 /** 267 * In some cases when we do not have any end-target, we play a simple slide-down animation. 268 * eg: Open an app from Overview/Task switcher such that there is no home-screen icon. 269 * eg: Exit the app using back gesture. 270 */ 271 public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78; 272 public static final int CUJ_SHADE_EXPAND_FROM_STATUS_BAR = 79; 273 public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80; 274 public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81; 275 276 public static final int CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER = 82; 277 278 private static final int LAST_CUJ = CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER; 279 private static final int NO_STATSD_LOGGING = -1; 280 281 // Used to convert CujType to InteractionType enum value for statsd logging. 282 // Use NO_STATSD_LOGGING in case the measurement for a given CUJ should not be logged to statsd. 283 @VisibleForTesting 284 public static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = new int[LAST_CUJ + 1]; 285 286 static { 287 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE; 288 CUJ_TO_STATSD_INTERACTION_TYPE[1] = NO_STATSD_LOGGING; // This is deprecated. 289 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_SCROLL_FLING] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING; 290 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_ROW_EXPAND] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_EXPAND; 291 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_ROW_SWIPE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE; 292 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_EXPAND_COLLAPSE; 293 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_SCROLL_SWIPE; 294 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS; 295 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON; 296 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_HOME] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME; 297 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_PIP] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP; 298 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_QUICK_SWITCH] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH; 299 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_HEADS_UP_APPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR; 300 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR; 301 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_ADD] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD; 302 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_REMOVE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_REMOVE; 303 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_APP_START] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH; 304 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_PASSWORD_APPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR; 305 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_PATTERN_APPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PATTERN_APPEAR; 306 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_PIN_APPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PIN_APPEAR; 307 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_DISAPPEAR; 308 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_PATTERN_DISAPPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PATTERN_DISAPPEAR; 309 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_PIN_DISAPPEAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PIN_DISAPPEAR; 310 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_TRANSITION_FROM_AOD] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_FROM_AOD; 311 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_TRANSITION_TO_AOD] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD; 312 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_OPEN_ALL_APPS] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS; 313 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_ALL_APPS_SCROLL] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL; 314 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_WIDGET; 315 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SETTINGS_PAGE_SCROLL] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL; 316 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_UNLOCK_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION; 317 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON; 318 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER; 319 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE; 320 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON; 321 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP; 322 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PIP_TRANSITION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION; 323 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION; 324 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_USER_SWITCH] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH; 325 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLASHSCREEN_AVD] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD; 326 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLASHSCREEN_EXIT_ANIM] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM; 327 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SCREEN_OFF] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF; 328 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SCREEN_OFF_SHOW_AOD] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD; 329 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_ONE_HANDED_ENTER_TRANSITION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_ENTER_TRANSITION; 330 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_ONE_HANDED_EXIT_TRANSITION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_EXIT_TRANSITION; 331 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_UNFOLD_ANIM] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM; 332 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS; 333 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS; 334 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SUW_LOADING_TO_NEXT_FLOW] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_NEXT_FLOW; 335 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SUW_LOADING_SCREEN_FOR_STATUS] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_SCREEN_FOR_STATUS; 336 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_ENTER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_ENTER; 337 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_EXIT] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_EXIT; 338 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_LAUNCH_CAMERA] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA; 339 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_RESIZE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_RESIZE; 340 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SETTINGS_SLIDER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER; 341 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_TAKE_SCREENSHOT] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT; 342 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_VOLUME_CONTROL] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL; 343 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_BIOMETRIC_PROMPT_TRANSITION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION; 344 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SETTINGS_TOGGLE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE; 345 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_DIALOG_OPEN] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_DIALOG_OPEN; 346 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_USER_DIALOG_OPEN] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_DIALOG_OPEN; 347 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_TASKBAR_EXPAND] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TASKBAR_EXPAND; 348 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_TASKBAR_COLLAPSE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TASKBAR_COLLAPSE; 349 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_CLEAR_ALL] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_CLEAR_ALL; 350 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNLOCK_ENTRANCE_ANIMATION; 351 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_OCCLUSION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_OCCLUSION; 352 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_RECENTS_SCROLLING] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__RECENTS_SCROLLING; 353 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS; 354 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE; 355 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME; 356 CUJ_TO_STATSD_INTERACTION_TYPE[69] = NO_STATSD_LOGGING; // This is deprecated. 357 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION; 358 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_OPEN_SEARCH_RESULT] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_SEARCH_RESULT; 359 // 72 - 77 are reserved for b/281564325. 360 CUJ_TO_STATSD_INTERACTION_TYPE[72] = NO_STATSD_LOGGING; 361 CUJ_TO_STATSD_INTERACTION_TYPE[73] = NO_STATSD_LOGGING; 362 CUJ_TO_STATSD_INTERACTION_TYPE[74] = NO_STATSD_LOGGING; 363 CUJ_TO_STATSD_INTERACTION_TYPE[75] = NO_STATSD_LOGGING; 364 CUJ_TO_STATSD_INTERACTION_TYPE[76] = NO_STATSD_LOGGING; 365 CUJ_TO_STATSD_INTERACTION_TYPE[77] = NO_STATSD_LOGGING; 366 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK; 367 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_EXPAND_FROM_STATUS_BAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR; 368 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_SHOW_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_SHOW_ANIMATION; 369 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_HIDE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION; 370 CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_DOUBLE_TAP_DIVIDER; 371 } 372 373 private static class InstanceHolder { 374 public static final InteractionJankMonitor INSTANCE = 375 new InteractionJankMonitor(new HandlerThread(DEFAULT_WORKER_NAME)); 376 } 377 378 private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener = 379 this::updateProperties; 380 381 @GuardedBy("mLock") 382 private final SparseArray<FrameTracker> mRunningTrackers; 383 @GuardedBy("mLock") 384 private final SparseArray<Runnable> mTimeoutActions; 385 private final HandlerThread mWorker; 386 private final DisplayResolutionTracker mDisplayResolutionTracker; 387 private final Object mLock = new Object(); 388 private @ColorInt int mDebugBgColor = Color.CYAN; 389 private double mDebugYOffset = 0.1; 390 private InteractionMonitorDebugOverlay mDebugOverlay; 391 392 private volatile boolean mEnabled = DEFAULT_ENABLED; 393 private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL; 394 private int mTraceThresholdMissedFrames = DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES; 395 private int mTraceThresholdFrameTimeMillis = DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS; 396 397 /** @hide */ 398 @IntDef({ 399 CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, 400 CUJ_NOTIFICATION_SHADE_SCROLL_FLING, 401 CUJ_NOTIFICATION_SHADE_ROW_EXPAND, 402 CUJ_NOTIFICATION_SHADE_ROW_SWIPE, 403 CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, 404 CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE, 405 CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS, 406 CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON, 407 CUJ_LAUNCHER_APP_CLOSE_TO_HOME, 408 CUJ_LAUNCHER_APP_CLOSE_TO_PIP, 409 CUJ_LAUNCHER_QUICK_SWITCH, 410 CUJ_NOTIFICATION_HEADS_UP_APPEAR, 411 CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR, 412 CUJ_NOTIFICATION_ADD, 413 CUJ_NOTIFICATION_REMOVE, 414 CUJ_NOTIFICATION_APP_START, 415 CUJ_LOCKSCREEN_PASSWORD_APPEAR, 416 CUJ_LOCKSCREEN_PATTERN_APPEAR, 417 CUJ_LOCKSCREEN_PIN_APPEAR, 418 CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR, 419 CUJ_LOCKSCREEN_PATTERN_DISAPPEAR, 420 CUJ_LOCKSCREEN_PIN_DISAPPEAR, 421 CUJ_LOCKSCREEN_TRANSITION_FROM_AOD, 422 CUJ_LOCKSCREEN_TRANSITION_TO_AOD, 423 CUJ_LAUNCHER_OPEN_ALL_APPS, 424 CUJ_LAUNCHER_ALL_APPS_SCROLL, 425 CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET, 426 CUJ_SETTINGS_PAGE_SCROLL, 427 CUJ_LOCKSCREEN_UNLOCK_ANIMATION, 428 CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON, 429 CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER, 430 CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, 431 CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON, 432 CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP, 433 CUJ_PIP_TRANSITION, 434 CUJ_WALLPAPER_TRANSITION, 435 CUJ_USER_SWITCH, 436 CUJ_SPLASHSCREEN_AVD, 437 CUJ_SPLASHSCREEN_EXIT_ANIM, 438 CUJ_SCREEN_OFF, 439 CUJ_SCREEN_OFF_SHOW_AOD, 440 CUJ_ONE_HANDED_ENTER_TRANSITION, 441 CUJ_ONE_HANDED_EXIT_TRANSITION, 442 CUJ_UNFOLD_ANIM, 443 CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS, 444 CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS, 445 CUJ_SUW_LOADING_TO_NEXT_FLOW, 446 CUJ_SUW_LOADING_SCREEN_FOR_STATUS, 447 CUJ_SPLIT_SCREEN_ENTER, 448 CUJ_SPLIT_SCREEN_EXIT, 449 CUJ_LOCKSCREEN_LAUNCH_CAMERA, 450 CUJ_SPLIT_SCREEN_RESIZE, 451 CUJ_SETTINGS_SLIDER, 452 CUJ_TAKE_SCREENSHOT, 453 CUJ_VOLUME_CONTROL, 454 CUJ_BIOMETRIC_PROMPT_TRANSITION, 455 CUJ_SETTINGS_TOGGLE, 456 CUJ_SHADE_DIALOG_OPEN, 457 CUJ_USER_DIALOG_OPEN, 458 CUJ_TASKBAR_EXPAND, 459 CUJ_TASKBAR_COLLAPSE, 460 CUJ_SHADE_CLEAR_ALL, 461 CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION, 462 CUJ_LOCKSCREEN_OCCLUSION, 463 CUJ_RECENTS_SCROLLING, 464 CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS, 465 CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE, 466 CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME, 467 CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION, 468 CUJ_LAUNCHER_OPEN_SEARCH_RESULT, 469 CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK, 470 CUJ_SHADE_EXPAND_FROM_STATUS_BAR, 471 CUJ_IME_INSETS_SHOW_ANIMATION, 472 CUJ_IME_INSETS_HIDE_ANIMATION, 473 CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER, 474 }) 475 @Retention(RetentionPolicy.SOURCE) 476 public @interface CujType { 477 } 478 479 /** 480 * Get the singleton of InteractionJankMonitor. 481 * 482 * @return instance of InteractionJankMonitor 483 */ getInstance()484 public static InteractionJankMonitor getInstance() { 485 return InstanceHolder.INSTANCE; 486 } 487 488 /** 489 * This constructor should be only public to tests. 490 * 491 * @param worker the worker thread for the callbacks 492 */ 493 @VisibleForTesting 494 @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) InteractionJankMonitor(@onNull HandlerThread worker)495 public InteractionJankMonitor(@NonNull HandlerThread worker) { 496 mRunningTrackers = new SparseArray<>(); 497 mTimeoutActions = new SparseArray<>(); 498 mWorker = worker; 499 mWorker.start(); 500 mDisplayResolutionTracker = new DisplayResolutionTracker(worker.getThreadHandler()); 501 mSamplingInterval = DEFAULT_SAMPLING_INTERVAL; 502 mEnabled = DEFAULT_ENABLED; 503 504 final Context context = ActivityThread.currentApplication(); 505 if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) != PERMISSION_GRANTED) { 506 if (DEBUG) { 507 Log.d(TAG, "Initialized the InteractionJankMonitor." 508 + " (No READ_DEVICE_CONFIG permission to change configs)" 509 + " enabled=" + mEnabled + ", interval=" + mSamplingInterval 510 + ", missedFrameThreshold=" + mTraceThresholdMissedFrames 511 + ", frameTimeThreshold=" + mTraceThresholdFrameTimeMillis 512 + ", package=" + context.getPackageName()); 513 } 514 return; 515 } 516 517 // Post initialization to the background in case we're running on the main thread. 518 mWorker.getThreadHandler().post( 519 () -> { 520 try { 521 mPropertiesChangedListener.onPropertiesChanged( 522 DeviceConfig.getProperties(NAMESPACE_INTERACTION_JANK_MONITOR)); 523 DeviceConfig.addOnPropertiesChangedListener( 524 NAMESPACE_INTERACTION_JANK_MONITOR, 525 new HandlerExecutor(mWorker.getThreadHandler()), 526 mPropertiesChangedListener); 527 } catch (SecurityException ex) { 528 Log.d(TAG, "Can't get properties: READ_DEVICE_CONFIG granted=" 529 + context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) 530 + ", package=" + context.getPackageName()); 531 } 532 }); 533 } 534 535 /** 536 * Creates a {@link FrameTracker} instance. 537 * 538 * @param config the config used in instrumenting 539 * @param session the session associates with this tracker 540 * @return instance of the FrameTracker 541 */ 542 @VisibleForTesting createFrameTracker(Configuration config, Session session)543 public FrameTracker createFrameTracker(Configuration config, Session session) { 544 final View view = config.mView; 545 546 if (!config.hasValidView()) { 547 boolean attached = false; 548 boolean hasViewRoot = false; 549 boolean hasRenderer = false; 550 if (view != null) { 551 attached = view.isAttachedToWindow(); 552 hasViewRoot = view.getViewRootImpl() != null; 553 hasRenderer = view.getThreadedRenderer() != null; 554 } 555 Log.d(TAG, "create FrameTracker fails: view=" + view 556 + ", attached=" + attached + ", hasViewRoot=" + hasViewRoot 557 + ", hasRenderer=" + hasRenderer, new Throwable()); 558 return null; 559 } 560 561 final ThreadedRendererWrapper threadedRenderer = 562 view == null ? null : new ThreadedRendererWrapper(view.getThreadedRenderer()); 563 final ViewRootWrapper viewRoot = 564 view == null ? null : new ViewRootWrapper(view.getViewRootImpl()); 565 final SurfaceControlWrapper surfaceControl = new SurfaceControlWrapper(); 566 final ChoreographerWrapper choreographer = 567 new ChoreographerWrapper(Choreographer.getInstance()); 568 final FrameTrackerListener eventsListener = (s, act) -> handleCujEvents(act, s); 569 final FrameMetricsWrapper frameMetrics = new FrameMetricsWrapper(); 570 571 return new FrameTracker(this, session, config.getHandler(), threadedRenderer, viewRoot, 572 surfaceControl, choreographer, frameMetrics, 573 new FrameTracker.StatsLogWrapper(mDisplayResolutionTracker), 574 mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, 575 eventsListener, config); 576 } 577 578 @UiThread handleCujEvents(String action, Session session)579 private void handleCujEvents(String action, Session session) { 580 // Clear the running and timeout tasks if the end / cancel was fired within the tracker. 581 // Or we might have memory leaks. 582 if (needRemoveTasks(action, session)) { 583 getTracker(session.getCuj()).getHandler().runWithScissors(() -> { 584 removeTimeout(session.getCuj()); 585 removeTracker(session.getCuj(), session.getReason()); 586 }, EXECUTOR_TASK_TIMEOUT); 587 } 588 } 589 needRemoveTasks(String action, Session session)590 private boolean needRemoveTasks(String action, Session session) { 591 final boolean badEnd = action.equals(ACTION_SESSION_END) 592 && session.getReason() != REASON_END_NORMAL; 593 final boolean badCancel = action.equals(ACTION_SESSION_CANCEL) 594 && !(session.getReason() == REASON_CANCEL_NORMAL 595 || session.getReason() == REASON_CANCEL_TIMEOUT); 596 return badEnd || badCancel; 597 } 598 removeTimeout(@ujType int cujType)599 private void removeTimeout(@CujType int cujType) { 600 synchronized (mLock) { 601 Runnable timeout = mTimeoutActions.get(cujType); 602 if (timeout != null) { 603 getTracker(cujType).getHandler().removeCallbacks(timeout); 604 mTimeoutActions.remove(cujType); 605 } 606 } 607 } 608 609 /** 610 * @param cujType cuj type 611 * @return true if the cuj is under instrumenting, false otherwise. 612 */ isInstrumenting(@ujType int cujType)613 public boolean isInstrumenting(@CujType int cujType) { 614 synchronized (mLock) { 615 return mRunningTrackers.contains(cujType); 616 } 617 } 618 619 /** 620 * Begins a trace session. 621 * 622 * @param v an attached view. 623 * @param cujType the specific {@link InteractionJankMonitor.CujType}. 624 * @return boolean true if the tracker is started successfully, false otherwise. 625 */ begin(View v, @CujType int cujType)626 public boolean begin(View v, @CujType int cujType) { 627 try { 628 return begin(Configuration.Builder.withView(cujType, v)); 629 } catch (IllegalArgumentException ex) { 630 Log.d(TAG, "Build configuration failed!", ex); 631 return false; 632 } 633 } 634 635 /** 636 * Begins a trace session. 637 * 638 * @param builder the builder of the configurations for instrumenting the CUJ. 639 * @return boolean true if the tracker is begun successfully, false otherwise. 640 */ begin(@onNull Configuration.Builder builder)641 public boolean begin(@NonNull Configuration.Builder builder) { 642 try { 643 final Configuration config = builder.build(); 644 postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> { 645 EventLogTags.writeJankCujEventsBeginRequest( 646 config.mCujType, unixNanos, elapsedNanos, realtimeNanos, config.mTag); 647 }); 648 final TrackerResult result = new TrackerResult(); 649 final boolean success = config.getHandler().runWithScissors( 650 () -> result.mResult = beginInternal(config), EXECUTOR_TASK_TIMEOUT); 651 if (!success) { 652 Log.d(TAG, "begin failed due to timeout, CUJ=" + getNameOfCuj(config.mCujType)); 653 return false; 654 } 655 return result.mResult; 656 } catch (IllegalArgumentException ex) { 657 Log.d(TAG, "Build configuration failed!", ex); 658 return false; 659 } 660 } 661 662 @UiThread beginInternal(@onNull Configuration conf)663 private boolean beginInternal(@NonNull Configuration conf) { 664 int cujType = conf.mCujType; 665 if (!shouldMonitor(cujType)) return false; 666 FrameTracker tracker = getTracker(cujType); 667 // Skip subsequent calls if we already have an ongoing tracing. 668 if (tracker != null) return false; 669 670 // begin a new trace session. 671 tracker = createFrameTracker(conf, new Session(cujType, conf.mTag)); 672 if (tracker == null) return false; 673 putTracker(cujType, tracker); 674 tracker.begin(); 675 676 // Cancel the trace if we don't get an end() call in specified duration. 677 scheduleTimeoutAction( 678 cujType, conf.mTimeout, () -> cancel(cujType, REASON_CANCEL_TIMEOUT)); 679 return true; 680 } 681 682 /** 683 * Check if the monitoring is enabled and if it should be sampled. 684 */ 685 @SuppressWarnings("RandomModInteger") 686 @VisibleForTesting shouldMonitor(@ujType int cujType)687 public boolean shouldMonitor(@CujType int cujType) { 688 boolean shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0; 689 if (!mEnabled || !shouldSample) { 690 if (DEBUG) { 691 Log.d(TAG, "Skip monitoring cuj: " + getNameOfCuj(cujType) 692 + ", enable=" + mEnabled + ", debuggable=" + DEFAULT_ENABLED 693 + ", sample=" + shouldSample + ", interval=" + mSamplingInterval); 694 } 695 return false; 696 } 697 return true; 698 } 699 700 /** 701 * Schedules a timeout action. 702 * @param cuj cuj type 703 * @param timeout duration to timeout 704 * @param action action once timeout 705 */ 706 @VisibleForTesting scheduleTimeoutAction(@ujType int cuj, long timeout, Runnable action)707 public void scheduleTimeoutAction(@CujType int cuj, long timeout, Runnable action) { 708 synchronized (mLock) { 709 mTimeoutActions.put(cuj, action); 710 getTracker(cuj).getHandler().postDelayed(action, timeout); 711 } 712 } 713 714 /** 715 * Ends a trace session. 716 * 717 * @param cujType the specific {@link InteractionJankMonitor.CujType}. 718 * @return boolean true if the tracker is ended successfully, false otherwise. 719 */ end(@ujType int cujType)720 public boolean end(@CujType int cujType) { 721 postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> { 722 EventLogTags.writeJankCujEventsEndRequest( 723 cujType, unixNanos, elapsedNanos, realtimeNanos); 724 }); 725 FrameTracker tracker = getTracker(cujType); 726 // Skip this call since we haven't started a trace yet. 727 if (tracker == null) return false; 728 try { 729 final TrackerResult result = new TrackerResult(); 730 final boolean success = tracker.getHandler().runWithScissors( 731 () -> result.mResult = endInternal(cujType), EXECUTOR_TASK_TIMEOUT); 732 if (!success) { 733 Log.d(TAG, "end failed due to timeout, CUJ=" + getNameOfCuj(cujType)); 734 return false; 735 } 736 return result.mResult; 737 } catch (IllegalArgumentException ex) { 738 Log.d(TAG, "Execute end task failed!", ex); 739 return false; 740 } 741 } 742 743 @UiThread endInternal(@ujType int cujType)744 private boolean endInternal(@CujType int cujType) { 745 // remove the timeout action first. 746 removeTimeout(cujType); 747 FrameTracker tracker = getTracker(cujType); 748 if (tracker == null) return false; 749 // if the end call doesn't return true, another thread is handling end of the cuj. 750 if (tracker.end(REASON_END_NORMAL)) { 751 removeTracker(cujType, REASON_END_NORMAL); 752 } 753 return true; 754 } 755 756 /** 757 * Cancels the trace session. 758 * 759 * @return boolean true if the tracker is cancelled successfully, false otherwise. 760 */ cancel(@ujType int cujType)761 public boolean cancel(@CujType int cujType) { 762 postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> { 763 EventLogTags.writeJankCujEventsCancelRequest( 764 cujType, unixNanos, elapsedNanos, realtimeNanos); 765 }); 766 return cancel(cujType, REASON_CANCEL_NORMAL); 767 } 768 769 /** 770 * Cancels the trace session. 771 * 772 * @return boolean true if the tracker is cancelled successfully, false otherwise. 773 */ 774 @VisibleForTesting cancel(@ujType int cujType, @Reasons int reason)775 public boolean cancel(@CujType int cujType, @Reasons int reason) { 776 FrameTracker tracker = getTracker(cujType); 777 // Skip this call since we haven't started a trace yet. 778 if (tracker == null) return false; 779 try { 780 final TrackerResult result = new TrackerResult(); 781 final boolean success = tracker.getHandler().runWithScissors( 782 () -> result.mResult = cancelInternal(cujType, reason), EXECUTOR_TASK_TIMEOUT); 783 if (!success) { 784 Log.d(TAG, "cancel failed due to timeout, CUJ=" + getNameOfCuj(cujType)); 785 return false; 786 } 787 return result.mResult; 788 } catch (IllegalArgumentException ex) { 789 Log.d(TAG, "Execute cancel task failed!", ex); 790 return false; 791 } 792 } 793 794 @UiThread cancelInternal(@ujType int cujType, @Reasons int reason)795 private boolean cancelInternal(@CujType int cujType, @Reasons int reason) { 796 // remove the timeout action first. 797 removeTimeout(cujType); 798 FrameTracker tracker = getTracker(cujType); 799 if (tracker == null) return false; 800 // if the cancel call doesn't return true, another thread is handling cancel of the cuj. 801 if (tracker.cancel(reason)) { 802 removeTracker(cujType, reason); 803 } 804 return true; 805 } 806 807 @UiThread putTracker(@ujType int cuj, @NonNull FrameTracker tracker)808 private void putTracker(@CujType int cuj, @NonNull FrameTracker tracker) { 809 synchronized (mLock) { 810 mRunningTrackers.put(cuj, tracker); 811 if (mDebugOverlay != null) { 812 mDebugOverlay.onTrackerAdded(cuj, tracker); 813 } 814 if (DEBUG) { 815 Log.d(TAG, "Added tracker for " + getNameOfCuj(cuj) 816 + ". mRunningTrackers=" + listNamesOfCujs(mRunningTrackers)); 817 } 818 } 819 } 820 getTracker(@ujType int cuj)821 private FrameTracker getTracker(@CujType int cuj) { 822 synchronized (mLock) { 823 return mRunningTrackers.get(cuj); 824 } 825 } 826 827 @UiThread removeTracker(@ujType int cuj, int reason)828 private void removeTracker(@CujType int cuj, int reason) { 829 synchronized (mLock) { 830 mRunningTrackers.remove(cuj); 831 if (mDebugOverlay != null) { 832 mDebugOverlay.onTrackerRemoved(cuj, reason, mRunningTrackers); 833 } 834 if (DEBUG) { 835 Log.d(TAG, "Removed tracker for " + getNameOfCuj(cuj) 836 + ". mRunningTrackers=" + listNamesOfCujs(mRunningTrackers)); 837 } 838 } 839 } 840 841 @WorkerThread updateProperties(DeviceConfig.Properties properties)842 private void updateProperties(DeviceConfig.Properties properties) { 843 mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, 844 DEFAULT_SAMPLING_INTERVAL); 845 mTraceThresholdMissedFrames = properties.getInt(SETTINGS_THRESHOLD_MISSED_FRAMES_KEY, 846 DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES); 847 mTraceThresholdFrameTimeMillis = properties.getInt( 848 SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY, 849 DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS); 850 // Never allow the debug overlay to be used on user builds 851 boolean debugOverlayEnabled = Build.IS_DEBUGGABLE && properties.getBoolean( 852 SETTINGS_DEBUG_OVERLAY_ENABLED_KEY, 853 DEFAULT_DEBUG_OVERLAY_ENABLED); 854 if (debugOverlayEnabled && mDebugOverlay == null) { 855 mDebugOverlay = new InteractionMonitorDebugOverlay(mLock, mDebugBgColor, mDebugYOffset); 856 } else if (!debugOverlayEnabled && mDebugOverlay != null) { 857 mDebugOverlay.dispose(); 858 mDebugOverlay = null; 859 } 860 // The memory visibility is powered by the volatile field, mEnabled. 861 mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED); 862 } 863 864 @VisibleForTesting getPropertiesChangedListener()865 public DeviceConfig.OnPropertiesChangedListener getPropertiesChangedListener() { 866 return mPropertiesChangedListener; 867 } 868 869 /** 870 * Triggers the perfetto daemon to collect and upload data. 871 */ 872 @VisibleForTesting trigger(Session session)873 public void trigger(Session session) { 874 mWorker.getThreadHandler().post( 875 () -> PerfettoTrigger.trigger(session.getPerfettoTrigger())); 876 } 877 878 /** 879 * A helper method to translate interaction type to CUJ name. 880 * 881 * @param interactionType the interaction type defined in AtomsProto.java 882 * @return the name of the interaction type 883 */ getNameOfInteraction(int interactionType)884 public static String getNameOfInteraction(int interactionType) { 885 // There is an offset amount of 1 between cujType and interactionType. 886 return getNameOfCuj(getCujTypeFromInteraction(interactionType)); 887 } 888 889 /** 890 * A helper method to translate interaction type to CUJ type. 891 * 892 * @param interactionType the interaction type defined in AtomsProto.java 893 * @return the integer in {@link CujType} 894 */ getCujTypeFromInteraction(int interactionType)895 private static int getCujTypeFromInteraction(int interactionType) { 896 return interactionType - 1; 897 } 898 899 /** 900 * Configures the debug overlay used for displaying interaction names on the screen while they 901 * occur. 902 * 903 * @param bgColor the background color of the box used to display the CUJ names 904 * @param yOffset number between 0 and 1 to indicate where the top of the box should be relative 905 * to the height of the screen 906 */ configDebugOverlay(@olorInt int bgColor, double yOffset)907 public void configDebugOverlay(@ColorInt int bgColor, double yOffset) { 908 mDebugBgColor = bgColor; 909 mDebugYOffset = yOffset; 910 } 911 912 /** 913 * A helper method for getting a string representation of all running CUJs. For example, 914 * "(LOCKSCREEN_TRANSITION_FROM_AOD, IME_INSETS_ANIMATION)" 915 */ listNamesOfCujs(SparseArray<FrameTracker> trackers)916 private static String listNamesOfCujs(SparseArray<FrameTracker> trackers) { 917 if (!DEBUG) { 918 return null; 919 } 920 StringBuilder sb = new StringBuilder(); 921 sb.append('('); 922 for (int i = 0; i < trackers.size(); i++) { 923 sb.append(getNameOfCuj(trackers.keyAt(i))); 924 if (i < trackers.size() - 1) { 925 sb.append(", "); 926 } 927 } 928 sb.append(')'); 929 return sb.toString(); 930 } 931 932 /** 933 * A helper method to translate CUJ type to CUJ name. 934 * 935 * @param cujType the cuj type defined in this file 936 * @return the name of the cuj type 937 */ getNameOfCuj(int cujType)938 public static String getNameOfCuj(int cujType) { 939 // Please note: 940 // 1. The length of the returned string shouldn't exceed MAX_LENGTH_OF_CUJ_NAME. 941 // 2. The returned string should be the same with the name defined in atoms.proto. 942 switch (cujType) { 943 case CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE: 944 return "NOTIFICATION_SHADE_EXPAND_COLLAPSE"; 945 case CUJ_NOTIFICATION_SHADE_SCROLL_FLING: 946 return "NOTIFICATION_SHADE_SCROLL_FLING"; 947 case CUJ_NOTIFICATION_SHADE_ROW_EXPAND: 948 return "NOTIFICATION_SHADE_ROW_EXPAND"; 949 case CUJ_NOTIFICATION_SHADE_ROW_SWIPE: 950 return "NOTIFICATION_SHADE_ROW_SWIPE"; 951 case CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE: 952 return "NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE"; 953 case CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE: 954 return "NOTIFICATION_SHADE_QS_SCROLL_SWIPE"; 955 case CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS: 956 return "LAUNCHER_APP_LAUNCH_FROM_RECENTS"; 957 case CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON: 958 return "LAUNCHER_APP_LAUNCH_FROM_ICON"; 959 case CUJ_LAUNCHER_APP_CLOSE_TO_HOME: 960 return "LAUNCHER_APP_CLOSE_TO_HOME"; 961 case CUJ_LAUNCHER_APP_CLOSE_TO_PIP: 962 return "LAUNCHER_APP_CLOSE_TO_PIP"; 963 case CUJ_LAUNCHER_QUICK_SWITCH: 964 return "LAUNCHER_QUICK_SWITCH"; 965 case CUJ_NOTIFICATION_HEADS_UP_APPEAR: 966 return "NOTIFICATION_HEADS_UP_APPEAR"; 967 case CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR: 968 return "NOTIFICATION_HEADS_UP_DISAPPEAR"; 969 case CUJ_NOTIFICATION_ADD: 970 return "NOTIFICATION_ADD"; 971 case CUJ_NOTIFICATION_REMOVE: 972 return "NOTIFICATION_REMOVE"; 973 case CUJ_NOTIFICATION_APP_START: 974 return "NOTIFICATION_APP_START"; 975 case CUJ_LOCKSCREEN_PASSWORD_APPEAR: 976 return "LOCKSCREEN_PASSWORD_APPEAR"; 977 case CUJ_LOCKSCREEN_PATTERN_APPEAR: 978 return "LOCKSCREEN_PATTERN_APPEAR"; 979 case CUJ_LOCKSCREEN_PIN_APPEAR: 980 return "LOCKSCREEN_PIN_APPEAR"; 981 case CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR: 982 return "LOCKSCREEN_PASSWORD_DISAPPEAR"; 983 case CUJ_LOCKSCREEN_PATTERN_DISAPPEAR: 984 return "LOCKSCREEN_PATTERN_DISAPPEAR"; 985 case CUJ_LOCKSCREEN_PIN_DISAPPEAR: 986 return "LOCKSCREEN_PIN_DISAPPEAR"; 987 case CUJ_LOCKSCREEN_TRANSITION_FROM_AOD: 988 return "LOCKSCREEN_TRANSITION_FROM_AOD"; 989 case CUJ_LOCKSCREEN_TRANSITION_TO_AOD: 990 return "LOCKSCREEN_TRANSITION_TO_AOD"; 991 case CUJ_LAUNCHER_OPEN_ALL_APPS : 992 return "LAUNCHER_OPEN_ALL_APPS"; 993 case CUJ_LAUNCHER_ALL_APPS_SCROLL: 994 return "LAUNCHER_ALL_APPS_SCROLL"; 995 case CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET: 996 return "LAUNCHER_APP_LAUNCH_FROM_WIDGET"; 997 case CUJ_SETTINGS_PAGE_SCROLL: 998 return "SETTINGS_PAGE_SCROLL"; 999 case CUJ_LOCKSCREEN_UNLOCK_ANIMATION: 1000 return "LOCKSCREEN_UNLOCK_ANIMATION"; 1001 case CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON: 1002 return "SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON"; 1003 case CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER: 1004 return "SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER"; 1005 case CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE: 1006 return "SHADE_APP_LAUNCH_FROM_QS_TILE"; 1007 case CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON: 1008 return "SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON"; 1009 case CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP: 1010 return "STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP"; 1011 case CUJ_PIP_TRANSITION: 1012 return "PIP_TRANSITION"; 1013 case CUJ_WALLPAPER_TRANSITION: 1014 return "WALLPAPER_TRANSITION"; 1015 case CUJ_USER_SWITCH: 1016 return "USER_SWITCH"; 1017 case CUJ_SPLASHSCREEN_AVD: 1018 return "SPLASHSCREEN_AVD"; 1019 case CUJ_SPLASHSCREEN_EXIT_ANIM: 1020 return "SPLASHSCREEN_EXIT_ANIM"; 1021 case CUJ_SCREEN_OFF: 1022 return "SCREEN_OFF"; 1023 case CUJ_SCREEN_OFF_SHOW_AOD: 1024 return "SCREEN_OFF_SHOW_AOD"; 1025 case CUJ_ONE_HANDED_ENTER_TRANSITION: 1026 return "ONE_HANDED_ENTER_TRANSITION"; 1027 case CUJ_ONE_HANDED_EXIT_TRANSITION: 1028 return "ONE_HANDED_EXIT_TRANSITION"; 1029 case CUJ_UNFOLD_ANIM: 1030 return "UNFOLD_ANIM"; 1031 case CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS: 1032 return "SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS"; 1033 case CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS: 1034 return "SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS"; 1035 case CUJ_SUW_LOADING_TO_NEXT_FLOW: 1036 return "SUW_LOADING_TO_NEXT_FLOW"; 1037 case CUJ_SUW_LOADING_SCREEN_FOR_STATUS: 1038 return "SUW_LOADING_SCREEN_FOR_STATUS"; 1039 case CUJ_SPLIT_SCREEN_ENTER: 1040 return "SPLIT_SCREEN_ENTER"; 1041 case CUJ_SPLIT_SCREEN_EXIT: 1042 return "SPLIT_SCREEN_EXIT"; 1043 case CUJ_LOCKSCREEN_LAUNCH_CAMERA: 1044 return "LOCKSCREEN_LAUNCH_CAMERA"; 1045 case CUJ_SPLIT_SCREEN_RESIZE: 1046 return "SPLIT_SCREEN_RESIZE"; 1047 case CUJ_SETTINGS_SLIDER: 1048 return "SETTINGS_SLIDER"; 1049 case CUJ_TAKE_SCREENSHOT: 1050 return "TAKE_SCREENSHOT"; 1051 case CUJ_VOLUME_CONTROL: 1052 return "VOLUME_CONTROL"; 1053 case CUJ_BIOMETRIC_PROMPT_TRANSITION: 1054 return "BIOMETRIC_PROMPT_TRANSITION"; 1055 case CUJ_SETTINGS_TOGGLE: 1056 return "SETTINGS_TOGGLE"; 1057 case CUJ_SHADE_DIALOG_OPEN: 1058 return "SHADE_DIALOG_OPEN"; 1059 case CUJ_USER_DIALOG_OPEN: 1060 return "USER_DIALOG_OPEN"; 1061 case CUJ_TASKBAR_EXPAND: 1062 return "TASKBAR_EXPAND"; 1063 case CUJ_TASKBAR_COLLAPSE: 1064 return "TASKBAR_COLLAPSE"; 1065 case CUJ_SHADE_CLEAR_ALL: 1066 return "SHADE_CLEAR_ALL"; 1067 case CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION: 1068 return "LAUNCHER_UNLOCK_ENTRANCE_ANIMATION"; 1069 case CUJ_LOCKSCREEN_OCCLUSION: 1070 return "LOCKSCREEN_OCCLUSION"; 1071 case CUJ_RECENTS_SCROLLING: 1072 return "RECENTS_SCROLLING"; 1073 case CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS: 1074 return "LAUNCHER_APP_SWIPE_TO_RECENTS"; 1075 case CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE: 1076 return "LAUNCHER_CLOSE_ALL_APPS_SWIPE"; 1077 case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME: 1078 return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME"; 1079 case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION: 1080 return "LOCKSCREEN_CLOCK_MOVE_ANIMATION"; 1081 case CUJ_LAUNCHER_OPEN_SEARCH_RESULT: 1082 return "LAUNCHER_OPEN_SEARCH_RESULT"; 1083 case CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK: 1084 return "LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK"; 1085 case CUJ_SHADE_EXPAND_FROM_STATUS_BAR: 1086 return "SHADE_EXPAND_FROM_STATUS_BAR"; 1087 case CUJ_IME_INSETS_SHOW_ANIMATION: 1088 return "IME_INSETS_SHOW_ANIMATION"; 1089 case CUJ_IME_INSETS_HIDE_ANIMATION: 1090 return "IME_INSETS_HIDE_ANIMATION"; 1091 case CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER: 1092 return "SPLIT_SCREEN_DOUBLE_TAP_DIVIDER"; 1093 } 1094 return "UNKNOWN"; 1095 } 1096 1097 private static class TrackerResult { 1098 private boolean mResult; 1099 } 1100 1101 /** 1102 * Configurations used while instrumenting the CUJ. <br/> 1103 * <b>It may refer to an attached view, don't use static reference for any purpose.</b> 1104 */ 1105 public static class Configuration { 1106 private final View mView; 1107 private final Context mContext; 1108 private final long mTimeout; 1109 private final String mTag; 1110 private final boolean mSurfaceOnly; 1111 private final SurfaceControl mSurfaceControl; 1112 private final @CujType int mCujType; 1113 private final boolean mDeferMonitor; 1114 private final Handler mHandler; 1115 1116 /** 1117 * A builder for building Configuration. {@link #setView(View)} is essential 1118 * if {@link #setSurfaceOnly(boolean)} is not set, otherwise both 1119 * {@link #setSurfaceControl(SurfaceControl)} and {@link #setContext(Context)} 1120 * are necessary<br/> 1121 * <b>It may refer to an attached view, don't use static reference for any purpose.</b> 1122 */ 1123 public static class Builder { 1124 private View mAttrView = null; 1125 private Context mAttrContext = null; 1126 private long mAttrTimeout = DEFAULT_TIMEOUT_MS; 1127 private String mAttrTag = ""; 1128 private boolean mAttrSurfaceOnly; 1129 private SurfaceControl mAttrSurfaceControl; 1130 private @CujType int mAttrCujType; 1131 private boolean mAttrDeferMonitor = true; 1132 1133 /** 1134 * Creates a builder which instruments only surface. 1135 * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}. 1136 * @param context context 1137 * @param surfaceControl surface control 1138 * @return builder 1139 */ withSurface(@ujType int cuj, @NonNull Context context, @NonNull SurfaceControl surfaceControl)1140 public static Builder withSurface(@CujType int cuj, @NonNull Context context, 1141 @NonNull SurfaceControl surfaceControl) { 1142 return new Builder(cuj) 1143 .setContext(context) 1144 .setSurfaceControl(surfaceControl) 1145 .setSurfaceOnly(true); 1146 } 1147 1148 /** 1149 * Creates a builder which instruments both surface and view. 1150 * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}. 1151 * @param view view 1152 * @return builder 1153 */ withView(@ujType int cuj, @NonNull View view)1154 public static Builder withView(@CujType int cuj, @NonNull View view) { 1155 return new Builder(cuj).setView(view) 1156 .setContext(view.getContext()); 1157 } 1158 Builder(@ujType int cuj)1159 private Builder(@CujType int cuj) { 1160 mAttrCujType = cuj; 1161 } 1162 1163 /** 1164 * Specifies a view, must be set if {@link #setSurfaceOnly(boolean)} is set to false. 1165 * @param view an attached view 1166 * @return builder 1167 */ setView(@onNull View view)1168 private Builder setView(@NonNull View view) { 1169 mAttrView = view; 1170 return this; 1171 } 1172 1173 /** 1174 * @param timeout duration to cancel the instrumentation in ms 1175 * @return builder 1176 */ setTimeout(long timeout)1177 public Builder setTimeout(long timeout) { 1178 mAttrTimeout = timeout; 1179 return this; 1180 } 1181 1182 /** 1183 * @param tag The postfix of the CUJ in the output trace. 1184 * It provides a brief description for the CUJ like the concrete class 1185 * who is dealing with the CUJ or the important state with the CUJ, etc. 1186 * @return builder 1187 */ setTag(@onNull String tag)1188 public Builder setTag(@NonNull String tag) { 1189 mAttrTag = tag; 1190 return this; 1191 } 1192 1193 /** 1194 * Indicates if only instrument with surface, 1195 * if true, must also setup with {@link #setContext(Context)} 1196 * and {@link #setSurfaceControl(SurfaceControl)}. 1197 * @param surfaceOnly true if only instrument with surface, false otherwise 1198 * @return builder Surface only builder. 1199 */ setSurfaceOnly(boolean surfaceOnly)1200 private Builder setSurfaceOnly(boolean surfaceOnly) { 1201 mAttrSurfaceOnly = surfaceOnly; 1202 return this; 1203 } 1204 1205 /** 1206 * Specifies a context, must set if {@link #setSurfaceOnly(boolean)} is set. 1207 */ setContext(Context context)1208 private Builder setContext(Context context) { 1209 mAttrContext = context; 1210 return this; 1211 } 1212 1213 /** 1214 * Specifies a surface control, must be set if {@link #setSurfaceOnly(boolean)} is set. 1215 */ setSurfaceControl(SurfaceControl surfaceControl)1216 private Builder setSurfaceControl(SurfaceControl surfaceControl) { 1217 mAttrSurfaceControl = surfaceControl; 1218 return this; 1219 } 1220 1221 /** 1222 * Indicates if the instrument should be deferred to the next frame. 1223 * @param defer true if the instrument should be deferred to the next frame. 1224 * @return builder 1225 */ setDeferMonitorForAnimationStart(boolean defer)1226 public Builder setDeferMonitorForAnimationStart(boolean defer) { 1227 mAttrDeferMonitor = defer; 1228 return this; 1229 } 1230 1231 /** 1232 * Builds the {@link Configuration} instance 1233 * @return the instance of {@link Configuration} 1234 * @throws IllegalArgumentException if any invalid attribute is set 1235 */ build()1236 public Configuration build() throws IllegalArgumentException { 1237 return new Configuration( 1238 mAttrCujType, mAttrView, mAttrTag, mAttrTimeout, 1239 mAttrSurfaceOnly, mAttrContext, mAttrSurfaceControl, 1240 mAttrDeferMonitor); 1241 } 1242 } 1243 Configuration(@ujType int cuj, View view, String tag, long timeout, boolean surfaceOnly, Context context, SurfaceControl surfaceControl, boolean deferMonitor)1244 private Configuration(@CujType int cuj, View view, String tag, long timeout, 1245 boolean surfaceOnly, Context context, SurfaceControl surfaceControl, 1246 boolean deferMonitor) { 1247 mCujType = cuj; 1248 mTag = tag; 1249 mTimeout = timeout; 1250 mView = view; 1251 mSurfaceOnly = surfaceOnly; 1252 mContext = context != null 1253 ? context 1254 : (view != null ? view.getContext().getApplicationContext() : null); 1255 mSurfaceControl = surfaceControl; 1256 mDeferMonitor = deferMonitor; 1257 validate(); 1258 mHandler = mSurfaceOnly ? mContext.getMainThreadHandler() : mView.getHandler(); 1259 } 1260 validate()1261 private void validate() { 1262 boolean shouldThrow = false; 1263 final StringBuilder msg = new StringBuilder(); 1264 1265 if (mTag == null) { 1266 shouldThrow = true; 1267 msg.append("Invalid tag; "); 1268 } 1269 if (mTimeout < 0) { 1270 shouldThrow = true; 1271 msg.append("Invalid timeout value; "); 1272 } 1273 if (mSurfaceOnly) { 1274 if (mContext == null) { 1275 shouldThrow = true; 1276 msg.append("Must pass in a context if only instrument surface; "); 1277 } 1278 if (mSurfaceControl == null || !mSurfaceControl.isValid()) { 1279 shouldThrow = true; 1280 msg.append("Must pass in a valid surface control if only instrument surface; "); 1281 } 1282 } else { 1283 if (!hasValidView()) { 1284 shouldThrow = true; 1285 boolean attached = false; 1286 boolean hasViewRoot = false; 1287 boolean hasRenderer = false; 1288 if (mView != null) { 1289 attached = mView.isAttachedToWindow(); 1290 hasViewRoot = mView.getViewRootImpl() != null; 1291 hasRenderer = mView.getThreadedRenderer() != null; 1292 } 1293 String err = "invalid view: view=" + mView + ", attached=" + attached 1294 + ", hasViewRoot=" + hasViewRoot + ", hasRenderer=" + hasRenderer; 1295 msg.append(err); 1296 } 1297 } 1298 if (shouldThrow) { 1299 throw new IllegalArgumentException(msg.toString()); 1300 } 1301 } 1302 hasValidView()1303 boolean hasValidView() { 1304 return mSurfaceOnly 1305 || (mView != null && mView.isAttachedToWindow() 1306 && mView.getViewRootImpl() != null && mView.getThreadedRenderer() != null); 1307 } 1308 1309 /** 1310 * @return true if only instrumenting surface, false otherwise 1311 */ isSurfaceOnly()1312 public boolean isSurfaceOnly() { 1313 return mSurfaceOnly; 1314 } 1315 1316 /** 1317 * @return the surafce control which is instrumenting 1318 */ getSurfaceControl()1319 public SurfaceControl getSurfaceControl() { 1320 return mSurfaceControl; 1321 } 1322 1323 @VisibleForTesting 1324 /** 1325 * @return a view which is attached to the view tree. 1326 */ getView()1327 public View getView() { 1328 return mView; 1329 } 1330 1331 /** 1332 * @return true if the monitoring should be deferred to the next frame, false otherwise. 1333 */ shouldDeferMonitor()1334 public boolean shouldDeferMonitor() { 1335 return mDeferMonitor; 1336 } 1337 1338 @VisibleForTesting getHandler()1339 public Handler getHandler() { 1340 return mHandler; 1341 } 1342 1343 /** 1344 * @return the ID of the display this interaction in on. 1345 */ 1346 @VisibleForTesting getDisplayId()1347 public int getDisplayId() { 1348 return (mSurfaceOnly ? mContext : mView.getContext()).getDisplayId(); 1349 } 1350 } 1351 1352 /** 1353 * A class to represent a session. 1354 */ 1355 public static class Session { 1356 @CujType 1357 private final int mCujType; 1358 private final long mTimeStamp; 1359 @Reasons 1360 private int mReason = REASON_END_UNKNOWN; 1361 private final String mName; 1362 Session(@ujType int cujType, @NonNull String postfix)1363 public Session(@CujType int cujType, @NonNull String postfix) { 1364 mCujType = cujType; 1365 mTimeStamp = System.nanoTime(); 1366 mName = generateSessionName(getNameOfCuj(cujType), postfix); 1367 } 1368 generateSessionName(@onNull String cujName, @NonNull String cujPostfix)1369 private String generateSessionName(@NonNull String cujName, @NonNull String cujPostfix) { 1370 final boolean hasPostfix = !TextUtils.isEmpty(cujPostfix); 1371 // We assert that the cujName shouldn't exceed MAX_LENGTH_OF_CUJ_NAME. 1372 if (cujName.length() > MAX_LENGTH_OF_CUJ_NAME) { 1373 throw new IllegalArgumentException(TextUtils.formatSimple( 1374 "The length of cuj name <%s> exceeds %d", cujName, MAX_LENGTH_OF_CUJ_NAME)); 1375 } 1376 if (hasPostfix) { 1377 final int remaining = MAX_LENGTH_SESSION_NAME - cujName.length(); 1378 if (cujPostfix.length() > remaining) { 1379 cujPostfix = cujPostfix.substring(0, remaining - 3).concat("..."); 1380 } 1381 } 1382 // The max length of the whole string should be: 1383 // 105 with postfix, 83 without postfix 1384 return hasPostfix 1385 ? TextUtils.formatSimple("J<%s::%s>", cujName, cujPostfix) 1386 : TextUtils.formatSimple("J<%s>", cujName); 1387 } 1388 1389 @CujType getCuj()1390 public int getCuj() { 1391 return mCujType; 1392 } 1393 getStatsdInteractionType()1394 public int getStatsdInteractionType() { 1395 return CUJ_TO_STATSD_INTERACTION_TYPE[mCujType]; 1396 } 1397 1398 /** Describes whether the measurement from this session should be written to statsd. */ logToStatsd()1399 public boolean logToStatsd() { 1400 return getStatsdInteractionType() != NO_STATSD_LOGGING; 1401 } 1402 getPerfettoTrigger()1403 public String getPerfettoTrigger() { 1404 return String.format(Locale.US, "com.android.telemetry.interaction-jank-monitor-%d", 1405 mCujType); 1406 } 1407 getName()1408 public String getName() { 1409 return mName; 1410 } 1411 getTimeStamp()1412 public long getTimeStamp() { 1413 return mTimeStamp; 1414 } 1415 setReason(@easons int reason)1416 public void setReason(@Reasons int reason) { 1417 mReason = reason; 1418 } 1419 1420 @Reasons getReason()1421 public int getReason() { 1422 return mReason; 1423 } 1424 } 1425 1426 @FunctionalInterface 1427 private interface TimeFunction { invoke(long unixNanos, long elapsedNanos, long realtimeNanos)1428 void invoke(long unixNanos, long elapsedNanos, long realtimeNanos); 1429 } 1430 postEventLogToWorkerThread(TimeFunction logFunction)1431 private void postEventLogToWorkerThread(TimeFunction logFunction) { 1432 final Instant now = Instant.now(); 1433 final long unixNanos = TimeUnit.NANOSECONDS.convert(now.getEpochSecond(), TimeUnit.SECONDS) 1434 + now.getNano(); 1435 final long elapsedNanos = SystemClock.elapsedRealtimeNanos(); 1436 final long realtimeNanos = SystemClock.uptimeNanos(); 1437 1438 mWorker.getThreadHandler().post(() -> { 1439 logFunction.invoke(unixNanos, elapsedNanos, realtimeNanos); 1440 }); 1441 } 1442 } 1443