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.os.Trace.TRACE_TAG_APP; 18 19 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL; 20 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED; 21 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL; 22 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK; 23 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK; 24 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD; 25 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET; 26 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK; 27 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN; 28 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN; 29 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN; 30 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK; 31 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR; 32 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW; 33 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR; 34 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION; 35 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL; 36 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION; 37 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD; 38 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS; 39 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN; 40 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE; 41 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH; 42 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__UNKNOWN_ACTION; 43 import static com.android.internal.util.LatencyTracker.ActionProperties.ENABLE_SUFFIX; 44 import static com.android.internal.util.LatencyTracker.ActionProperties.LEGACY_TRACE_THRESHOLD_SUFFIX; 45 import static com.android.internal.util.LatencyTracker.ActionProperties.SAMPLE_INTERVAL_SUFFIX; 46 import static com.android.internal.util.LatencyTracker.ActionProperties.TRACE_THRESHOLD_SUFFIX; 47 48 import android.annotation.IntDef; 49 import android.annotation.NonNull; 50 import android.annotation.Nullable; 51 import android.content.Context; 52 import android.os.Build; 53 import android.os.ConditionVariable; 54 import android.os.SystemClock; 55 import android.os.Trace; 56 import android.provider.DeviceConfig; 57 import android.text.TextUtils; 58 import android.util.EventLog; 59 import android.util.Log; 60 import android.util.SparseArray; 61 62 import com.android.internal.annotations.GuardedBy; 63 import com.android.internal.annotations.VisibleForTesting; 64 import com.android.internal.logging.EventLogTags; 65 import com.android.internal.os.BackgroundThread; 66 67 import java.lang.annotation.Retention; 68 import java.lang.annotation.RetentionPolicy; 69 import java.util.Locale; 70 import java.util.concurrent.ThreadLocalRandom; 71 import java.util.concurrent.TimeUnit; 72 73 /** 74 * Class to track various latencies in SystemUI. It then writes the latency to statsd and also 75 * outputs it to logcat so these latencies can be captured by tests and then used for dashboards. 76 * <p> 77 * This is currently only in Keyguard so it can be shared between SystemUI and Keyguard, but 78 * eventually we'd want to merge these two packages together so Keyguard can use common classes 79 * that are shared with SystemUI. 80 */ 81 public class LatencyTracker { 82 private static final String TAG = "LatencyTracker"; 83 public static final String SETTINGS_ENABLED_KEY = "enabled"; 84 private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; 85 private static final boolean DEBUG = false; 86 /** Default to being enabled on debug builds. */ 87 private static final boolean DEFAULT_ENABLED = Build.IS_DEBUGGABLE; 88 /** Default to collecting data for 1/5 of all actions (randomly sampled). */ 89 private static final int DEFAULT_SAMPLING_INTERVAL = 5; 90 91 /** 92 * Time it takes until the first frame of the notification panel to be displayed while expanding 93 */ 94 public static final int ACTION_EXPAND_PANEL = 0; 95 96 /** 97 * Time it takes until the first frame of recents is drawn after invoking it with the button. 98 */ 99 public static final int ACTION_TOGGLE_RECENTS = 1; 100 101 /** 102 * Time between we get a fingerprint acquired signal until we start with the unlock animation 103 */ 104 public static final int ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 2; 105 106 /** 107 * Time it takes to check PIN/Pattern/Password. 108 */ 109 public static final int ACTION_CHECK_CREDENTIAL = 3; 110 111 /** 112 * Time it takes to check fully PIN/Pattern/Password, i.e. that's the time spent including the 113 * actions to unlock a user. 114 */ 115 public static final int ACTION_CHECK_CREDENTIAL_UNLOCKED = 4; 116 117 /** 118 * Time it takes to turn on the screen. 119 */ 120 public static final int ACTION_TURN_ON_SCREEN = 5; 121 122 /** 123 * Time it takes to rotate the screen. 124 */ 125 public static final int ACTION_ROTATE_SCREEN = 6; 126 127 /* 128 * Time between we get a face acquired signal until we start with the unlock animation 129 */ 130 public static final int ACTION_FACE_WAKE_AND_UNLOCK = 7; 131 132 /** 133 * Time between the swipe-up gesture and window drawn of recents activity. 134 */ 135 public static final int ACTION_START_RECENTS_ANIMATION = 8; 136 137 /** 138 * Time it takes to for the camera based algorithm to rotate the screen. 139 */ 140 public static final int ACTION_ROTATE_SCREEN_CAMERA_CHECK = 9; 141 142 /** 143 * Time it takes the sensor to detect rotation. 144 */ 145 public static final int ACTION_ROTATE_SCREEN_SENSOR = 10; 146 147 /** 148 * Time it takes to start unlock animation . 149 */ 150 public static final int ACTION_LOCKSCREEN_UNLOCK = 11; 151 152 /** 153 * Time it takes to switch users. 154 */ 155 public static final int ACTION_USER_SWITCH = 12; 156 157 /** 158 * Time it takes to turn on the inner screen for a foldable device. 159 */ 160 public static final int ACTION_SWITCH_DISPLAY_UNFOLD = 13; 161 162 /** 163 * Time it takes for a UDFPS sensor to appear ready after it is touched. 164 */ 165 public static final int ACTION_UDFPS_ILLUMINATE = 14; 166 167 /** 168 * Time it takes for the gesture back affordance arrow to show up. 169 */ 170 public static final int ACTION_SHOW_BACK_ARROW = 15; 171 172 /** 173 * Time it takes for loading share sheet. 174 */ 175 public static final int ACTION_LOAD_SHARE_SHEET = 16; 176 177 /** 178 * Time it takes for showing the selection toolbar. 179 */ 180 public static final int ACTION_SHOW_SELECTION_TOOLBAR = 17; 181 182 /** 183 * Time it takes to show AOD display after folding the device. 184 */ 185 public static final int ACTION_FOLD_TO_AOD = 18; 186 187 /** 188 * Time it takes to show the {@link android.service.voice.VoiceInteractionSession} system UI 189 * after a {@link android.hardware.soundtrigger3.ISoundTriggerHw} voice trigger. 190 */ 191 public static final int ACTION_SHOW_VOICE_INTERACTION = 19; 192 193 /** 194 * Time it takes to request IME shown animation. 195 */ 196 public static final int ACTION_REQUEST_IME_SHOWN = 20; 197 198 /** 199 * Time it takes to request IME hidden animation. 200 */ 201 public static final int ACTION_REQUEST_IME_HIDDEN = 21; 202 203 /** 204 * Time it takes to load the animation frames in smart space doorbell card. 205 * It measures the duration from the images uris are passed into the view 206 * to all the frames are loaded. 207 * <p/> 208 * A long latency makes the doorbell animation looks janky until all the frames are loaded. 209 */ 210 public static final int ACTION_SMARTSPACE_DOORBELL = 22; 211 212 private static final int[] ACTIONS_ALL = { 213 ACTION_EXPAND_PANEL, 214 ACTION_TOGGLE_RECENTS, 215 ACTION_FINGERPRINT_WAKE_AND_UNLOCK, 216 ACTION_CHECK_CREDENTIAL, 217 ACTION_CHECK_CREDENTIAL_UNLOCKED, 218 ACTION_TURN_ON_SCREEN, 219 ACTION_ROTATE_SCREEN, 220 ACTION_FACE_WAKE_AND_UNLOCK, 221 ACTION_START_RECENTS_ANIMATION, 222 ACTION_ROTATE_SCREEN_CAMERA_CHECK, 223 ACTION_ROTATE_SCREEN_SENSOR, 224 ACTION_LOCKSCREEN_UNLOCK, 225 ACTION_USER_SWITCH, 226 ACTION_SWITCH_DISPLAY_UNFOLD, 227 ACTION_UDFPS_ILLUMINATE, 228 ACTION_SHOW_BACK_ARROW, 229 ACTION_LOAD_SHARE_SHEET, 230 ACTION_SHOW_SELECTION_TOOLBAR, 231 ACTION_FOLD_TO_AOD, 232 ACTION_SHOW_VOICE_INTERACTION, 233 ACTION_REQUEST_IME_SHOWN, 234 ACTION_REQUEST_IME_HIDDEN, 235 ACTION_SMARTSPACE_DOORBELL, 236 }; 237 238 /** @hide */ 239 @IntDef({ 240 ACTION_EXPAND_PANEL, 241 ACTION_TOGGLE_RECENTS, 242 ACTION_FINGERPRINT_WAKE_AND_UNLOCK, 243 ACTION_CHECK_CREDENTIAL, 244 ACTION_CHECK_CREDENTIAL_UNLOCKED, 245 ACTION_TURN_ON_SCREEN, 246 ACTION_ROTATE_SCREEN, 247 ACTION_FACE_WAKE_AND_UNLOCK, 248 ACTION_START_RECENTS_ANIMATION, 249 ACTION_ROTATE_SCREEN_CAMERA_CHECK, 250 ACTION_ROTATE_SCREEN_SENSOR, 251 ACTION_LOCKSCREEN_UNLOCK, 252 ACTION_USER_SWITCH, 253 ACTION_SWITCH_DISPLAY_UNFOLD, 254 ACTION_UDFPS_ILLUMINATE, 255 ACTION_SHOW_BACK_ARROW, 256 ACTION_LOAD_SHARE_SHEET, 257 ACTION_SHOW_SELECTION_TOOLBAR, 258 ACTION_FOLD_TO_AOD, 259 ACTION_SHOW_VOICE_INTERACTION, 260 ACTION_REQUEST_IME_SHOWN, 261 ACTION_REQUEST_IME_HIDDEN, 262 ACTION_SMARTSPACE_DOORBELL, 263 }) 264 @Retention(RetentionPolicy.SOURCE) 265 public @interface Action { 266 } 267 268 @VisibleForTesting 269 public static final int[] STATSD_ACTION = new int[] { 270 UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL, 271 UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS, 272 UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK, 273 UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL, 274 UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED, 275 UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN, 276 UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN, 277 UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK, 278 UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION, 279 UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK, 280 UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR, 281 UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK, 282 UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH, 283 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD, 284 UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE, 285 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW, 286 UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET, 287 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR, 288 UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD, 289 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION, 290 UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN, 291 UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN, 292 UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL, 293 }; 294 295 private static LatencyTracker sLatencyTracker; 296 297 private final Object mLock = new Object(); 298 @GuardedBy("mLock") 299 private final SparseArray<Session> mSessions = new SparseArray<>(); 300 @GuardedBy("mLock") 301 private final SparseArray<ActionProperties> mActionPropertiesMap = new SparseArray<>(); 302 @GuardedBy("mLock") 303 private boolean mEnabled; 304 @VisibleForTesting 305 public final ConditionVariable mDeviceConfigPropertiesUpdated = new ConditionVariable(); 306 getInstance(Context context)307 public static LatencyTracker getInstance(Context context) { 308 if (sLatencyTracker == null) { 309 synchronized (LatencyTracker.class) { 310 if (sLatencyTracker == null) { 311 sLatencyTracker = new LatencyTracker(); 312 } 313 } 314 } 315 return sLatencyTracker; 316 } 317 318 @VisibleForTesting LatencyTracker()319 public LatencyTracker() { 320 mEnabled = DEFAULT_ENABLED; 321 322 // Post initialization to the background in case we're running on the main thread. 323 BackgroundThread.getHandler().post(() -> this.updateProperties( 324 DeviceConfig.getProperties(DeviceConfig.NAMESPACE_LATENCY_TRACKER))); 325 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_LATENCY_TRACKER, 326 BackgroundThread.getExecutor(), this::updateProperties); 327 } 328 updateProperties(DeviceConfig.Properties properties)329 private void updateProperties(DeviceConfig.Properties properties) { 330 synchronized (mLock) { 331 int samplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, 332 DEFAULT_SAMPLING_INTERVAL); 333 mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED); 334 for (int action : ACTIONS_ALL) { 335 String actionName = getNameOfAction(STATSD_ACTION[action]).toLowerCase(Locale.ROOT); 336 int legacyActionTraceThreshold = properties.getInt( 337 actionName + LEGACY_TRACE_THRESHOLD_SUFFIX, -1); 338 mActionPropertiesMap.put(action, new ActionProperties(action, 339 properties.getBoolean(actionName + ENABLE_SUFFIX, mEnabled), 340 properties.getInt(actionName + SAMPLE_INTERVAL_SUFFIX, samplingInterval), 341 properties.getInt(actionName + TRACE_THRESHOLD_SUFFIX, 342 legacyActionTraceThreshold))); 343 } 344 if (DEBUG) { 345 Log.d(TAG, "updated action properties: " + mActionPropertiesMap); 346 } 347 } 348 mDeviceConfigPropertiesUpdated.open(); 349 } 350 351 /** 352 * A helper method to translate action type to name. 353 * 354 * @param atomsProtoAction the action type defined in AtomsProto.java 355 * @return the name of the action 356 */ getNameOfAction(int atomsProtoAction)357 public static String getNameOfAction(int atomsProtoAction) { 358 // Defined in AtomsProto.java 359 switch (atomsProtoAction) { 360 case UIACTION_LATENCY_REPORTED__ACTION__UNKNOWN_ACTION: 361 return "UNKNOWN"; 362 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL: 363 return "ACTION_EXPAND_PANEL"; 364 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS: 365 return "ACTION_TOGGLE_RECENTS"; 366 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK: 367 return "ACTION_FINGERPRINT_WAKE_AND_UNLOCK"; 368 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL: 369 return "ACTION_CHECK_CREDENTIAL"; 370 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED: 371 return "ACTION_CHECK_CREDENTIAL_UNLOCKED"; 372 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN: 373 return "ACTION_TURN_ON_SCREEN"; 374 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN: 375 return "ACTION_ROTATE_SCREEN"; 376 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK: 377 return "ACTION_FACE_WAKE_AND_UNLOCK"; 378 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION: 379 return "ACTION_START_RECENTS_ANIMATION"; 380 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK: 381 return "ACTION_ROTATE_SCREEN_CAMERA_CHECK"; 382 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR: 383 return "ACTION_ROTATE_SCREEN_SENSOR"; 384 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK: 385 return "ACTION_LOCKSCREEN_UNLOCK"; 386 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH: 387 return "ACTION_USER_SWITCH"; 388 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD: 389 return "ACTION_SWITCH_DISPLAY_UNFOLD"; 390 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE: 391 return "ACTION_UDFPS_ILLUMINATE"; 392 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW: 393 return "ACTION_SHOW_BACK_ARROW"; 394 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET: 395 return "ACTION_LOAD_SHARE_SHEET"; 396 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR: 397 return "ACTION_SHOW_SELECTION_TOOLBAR"; 398 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD: 399 return "ACTION_FOLD_TO_AOD"; 400 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION: 401 return "ACTION_SHOW_VOICE_INTERACTION"; 402 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN: 403 return "ACTION_REQUEST_IME_SHOWN"; 404 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN: 405 return "ACTION_REQUEST_IME_HIDDEN"; 406 case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL: 407 return "ACTION_SMARTSPACE_DOORBELL"; 408 default: 409 throw new IllegalArgumentException("Invalid action"); 410 } 411 } 412 getTraceNameOfAction(@ction int action, String tag)413 private static String getTraceNameOfAction(@Action int action, String tag) { 414 if (TextUtils.isEmpty(tag)) { 415 return "L<" + getNameOfAction(STATSD_ACTION[action]) + ">"; 416 } else { 417 return "L<" + getNameOfAction(STATSD_ACTION[action]) + "::" + tag + ">"; 418 } 419 } 420 getTraceTriggerNameForAction(@ction int action)421 private static String getTraceTriggerNameForAction(@Action int action) { 422 return "com.android.telemetry.latency-tracker-" + getNameOfAction(STATSD_ACTION[action]); 423 } 424 425 /** 426 * @deprecated Use {@link #isEnabled(Context, int)} 427 */ 428 @Deprecated isEnabled(Context ctx)429 public static boolean isEnabled(Context ctx) { 430 return getInstance(ctx).isEnabled(); 431 } 432 433 /** 434 * @deprecated Used {@link #isEnabled(int)} 435 */ 436 @Deprecated isEnabled()437 public boolean isEnabled() { 438 synchronized (mLock) { 439 return mEnabled; 440 } 441 } 442 isEnabled(Context ctx, int action)443 public static boolean isEnabled(Context ctx, int action) { 444 return getInstance(ctx).isEnabled(action); 445 } 446 isEnabled(int action)447 public boolean isEnabled(int action) { 448 synchronized (mLock) { 449 ActionProperties actionProperties = mActionPropertiesMap.get(action); 450 if (actionProperties != null) { 451 return actionProperties.isEnabled(); 452 } 453 return false; 454 } 455 } 456 457 /** 458 * Notifies that an action is starting. <s>This needs to be called from the main thread.</s> 459 * 460 * @param action The action to start. One of the ACTION_* values. 461 */ onActionStart(@ction int action)462 public void onActionStart(@Action int action) { 463 onActionStart(action, null); 464 } 465 466 /** 467 * Notifies that an action is starting. <s>This needs to be called from the main thread.</s> 468 * 469 * @param action The action to start. One of the ACTION_* values. 470 * @param tag The brief description of the action. 471 */ onActionStart(@ction int action, String tag)472 public void onActionStart(@Action int action, String tag) { 473 synchronized (mLock) { 474 if (!isEnabled(action)) { 475 return; 476 } 477 // skip if the action is already instrumenting. 478 if (mSessions.get(action) != null) { 479 return; 480 } 481 Session session = new Session(action, tag); 482 session.begin(() -> onActionCancel(action)); 483 mSessions.put(action, session); 484 485 if (DEBUG) { 486 Log.d(TAG, "onActionStart: " + session.name() + ", start=" + session.mStartRtc); 487 } 488 } 489 } 490 491 /** 492 * Notifies that an action has ended. <s>This needs to be called from the main thread.</s> 493 * 494 * @param action The action to end. One of the ACTION_* values. 495 */ onActionEnd(@ction int action)496 public void onActionEnd(@Action int action) { 497 synchronized (mLock) { 498 if (!isEnabled(action)) { 499 return; 500 } 501 Session session = mSessions.get(action); 502 if (session == null) { 503 return; 504 } 505 session.end(); 506 mSessions.delete(action); 507 logAction(action, session.duration()); 508 509 if (DEBUG) { 510 Log.d(TAG, "onActionEnd:" + session.name() + ", duration=" + session.duration()); 511 } 512 } 513 } 514 515 /** 516 * Notifies that an action has canceled. <s>This needs to be called from the main thread.</s> 517 * 518 * @param action The action to cancel. One of the ACTION_* values. 519 * @hide 520 */ onActionCancel(@ction int action)521 public void onActionCancel(@Action int action) { 522 synchronized (mLock) { 523 Session session = mSessions.get(action); 524 if (session == null) { 525 return; 526 } 527 session.cancel(); 528 mSessions.delete(action); 529 530 if (DEBUG) { 531 Log.d(TAG, "onActionCancel: " + session.name()); 532 } 533 } 534 } 535 536 /** 537 * Logs an action that has started and ended. This needs to be called from the main thread. 538 * 539 * @param action The action to end. One of the ACTION_* values. 540 * @param duration The duration of the action in ms. 541 */ logAction(@ction int action, int duration)542 public void logAction(@Action int action, int duration) { 543 boolean shouldSample; 544 int traceThreshold; 545 synchronized (mLock) { 546 ActionProperties actionProperties = mActionPropertiesMap.get(action); 547 if (actionProperties == null) { 548 return; 549 } 550 int nextRandNum = ThreadLocalRandom.current().nextInt( 551 actionProperties.getSamplingInterval()); 552 shouldSample = nextRandNum == 0; 553 traceThreshold = actionProperties.getTraceThreshold(); 554 } 555 556 if (traceThreshold > 0 && duration >= traceThreshold) { 557 PerfettoTrigger.trigger(getTraceTriggerNameForAction(action)); 558 } 559 560 logActionDeprecated(action, duration, shouldSample); 561 } 562 563 /** 564 * Logs an action that has started and ended. This needs to be called from the main thread. 565 * 566 * @param action The action to end. One of the ACTION_* values. 567 * @param duration The duration of the action in ms. 568 * @param writeToStatsLog Whether to write the measured latency to FrameworkStatsLog. 569 */ logActionDeprecated( @ction int action, int duration, boolean writeToStatsLog)570 public static void logActionDeprecated( 571 @Action int action, int duration, boolean writeToStatsLog) { 572 Log.i(TAG, getNameOfAction(STATSD_ACTION[action]) + " latency=" + duration); 573 EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration); 574 575 if (writeToStatsLog) { 576 FrameworkStatsLog.write( 577 FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED, STATSD_ACTION[action], duration); 578 } 579 } 580 581 static class Session { 582 @Action 583 private final int mAction; 584 private final String mTag; 585 private final String mName; 586 private Runnable mTimeoutRunnable; 587 private long mStartRtc = -1; 588 private long mEndRtc = -1; 589 Session(@ction int action, @Nullable String tag)590 Session(@Action int action, @Nullable String tag) { 591 mAction = action; 592 mTag = tag; 593 mName = TextUtils.isEmpty(mTag) 594 ? getNameOfAction(STATSD_ACTION[mAction]) 595 : getNameOfAction(STATSD_ACTION[mAction]) + "::" + mTag; 596 } 597 name()598 String name() { 599 return mName; 600 } 601 traceName()602 String traceName() { 603 return getTraceNameOfAction(mAction, mTag); 604 } 605 begin(@onNull Runnable timeoutAction)606 void begin(@NonNull Runnable timeoutAction) { 607 mStartRtc = SystemClock.elapsedRealtime(); 608 Trace.asyncTraceForTrackBegin(TRACE_TAG_APP, traceName(), traceName(), 0); 609 610 // start counting timeout. 611 mTimeoutRunnable = () -> { 612 Trace.instantForTrack(TRACE_TAG_APP, traceName(), "timeout"); 613 timeoutAction.run(); 614 }; 615 BackgroundThread.getHandler() 616 .postDelayed(mTimeoutRunnable, TimeUnit.SECONDS.toMillis(15)); 617 } 618 end()619 void end() { 620 mEndRtc = SystemClock.elapsedRealtime(); 621 Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), "end", 0); 622 BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); 623 mTimeoutRunnable = null; 624 } 625 cancel()626 void cancel() { 627 Trace.instantForTrack(TRACE_TAG_APP, traceName(), "cancel"); 628 Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), "cancel", 0); 629 BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); 630 mTimeoutRunnable = null; 631 } 632 duration()633 int duration() { 634 return (int) (mEndRtc - mStartRtc); 635 } 636 } 637 638 @VisibleForTesting 639 static class ActionProperties { 640 static final String ENABLE_SUFFIX = "_enable"; 641 static final String SAMPLE_INTERVAL_SUFFIX = "_sample_interval"; 642 // TODO: migrate all usages of the legacy trace theshold property 643 static final String LEGACY_TRACE_THRESHOLD_SUFFIX = ""; 644 static final String TRACE_THRESHOLD_SUFFIX = "_trace_threshold"; 645 646 @Action 647 private final int mAction; 648 private final boolean mEnabled; 649 private final int mSamplingInterval; 650 private final int mTraceThreshold; 651 ActionProperties( @ction int action, boolean enabled, int samplingInterval, int traceThreshold)652 ActionProperties( 653 @Action int action, 654 boolean enabled, 655 int samplingInterval, 656 int traceThreshold) { 657 this.mAction = action; 658 com.android.internal.util.AnnotationValidations.validate( 659 Action.class, null, mAction); 660 this.mEnabled = enabled; 661 this.mSamplingInterval = samplingInterval; 662 this.mTraceThreshold = traceThreshold; 663 } 664 665 @Action getAction()666 int getAction() { 667 return mAction; 668 } 669 isEnabled()670 boolean isEnabled() { 671 return mEnabled; 672 } 673 getSamplingInterval()674 int getSamplingInterval() { 675 return mSamplingInterval; 676 } 677 getTraceThreshold()678 int getTraceThreshold() { 679 return mTraceThreshold; 680 } 681 682 @Override toString()683 public String toString() { 684 return "ActionProperties{" 685 + " mAction=" + mAction 686 + ", mEnabled=" + mEnabled 687 + ", mSamplingInterval=" + mSamplingInterval 688 + ", mTraceThreshold=" + mTraceThreshold 689 + "}"; 690 } 691 } 692 } 693