1 // Copyright 2023 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base.jank_tracker; 6 7 import android.app.Activity; 8 import android.os.Build; 9 10 /** 11 * Class for recording janky frame metrics for a specific Activity. 12 * 13 * It should be constructed when the activity is created, recording starts and stops automatically 14 * based on activity state. When the activity is being destroyed {@link #destroy()} should be called 15 * to clear the activity state observer. All methods should be called from the UI thread. 16 */ 17 public class JankTrackerImpl implements JankTracker { 18 // We use the DEADLINE field in the Android FrameMetrics which was added in S. 19 private static final boolean IS_TRACKING_ENABLED = 20 Build.VERSION.SDK_INT >= Build.VERSION_CODES.S; 21 22 private JankTrackerStateController mController; 23 private JankReportingScheduler mReportingScheduler; 24 25 /** 26 * Creates a new JankTracker instance tracking UI rendering of an activity. Metric recording 27 * starts when the activity starts, and it's paused when the activity stops. 28 */ JankTrackerImpl(Activity activity)29 public JankTrackerImpl(Activity activity) { 30 FrameMetricsStore metricsStore = new FrameMetricsStore(); 31 if (!constructInternalPreController(new JankReportingScheduler(metricsStore))) return; 32 33 constructInternalFinal( 34 new JankActivityTracker( 35 activity, new FrameMetricsListener(metricsStore), mReportingScheduler)); 36 } 37 38 /** 39 * Creates a new JankTracker which allows the controller to determine when it should start and 40 * stop metric scenarios/collection. 41 */ JankTrackerImpl(JankTrackerStateController controller)42 public JankTrackerImpl(JankTrackerStateController controller) { 43 if (!constructInternalPreController(controller.mReportingScheduler)) return; 44 constructInternalFinal(controller); 45 } 46 constructInternalPreController(JankReportingScheduler scheduler)47 private boolean constructInternalPreController(JankReportingScheduler scheduler) { 48 if (!IS_TRACKING_ENABLED) { 49 mReportingScheduler = null; 50 mController = null; 51 return false; 52 } 53 mReportingScheduler = scheduler; 54 return true; 55 } 56 constructInternalFinal(JankTrackerStateController controller)57 private void constructInternalFinal(JankTrackerStateController controller) { 58 mController = controller; 59 mController.initialize(); 60 } 61 62 @Override startTrackingScenario(@ankScenario int scenario)63 public void startTrackingScenario(@JankScenario int scenario) { 64 if (!IS_TRACKING_ENABLED) return; 65 66 mReportingScheduler.startTrackingScenario(scenario); 67 } 68 69 @Override finishTrackingScenario(@ankScenario int scenario)70 public void finishTrackingScenario(@JankScenario int scenario) { 71 finishTrackingScenario(scenario, -1); 72 } 73 74 @Override finishTrackingScenario(@ankScenario int scenario, long endScenarioTimeNs)75 public void finishTrackingScenario(@JankScenario int scenario, long endScenarioTimeNs) { 76 if (!IS_TRACKING_ENABLED) return; 77 78 mReportingScheduler.finishTrackingScenario(scenario, endScenarioTimeNs); 79 } 80 81 /** Stops listening for Activity state changes. */ 82 @Override destroy()83 public void destroy() { 84 if (!IS_TRACKING_ENABLED) return; 85 86 mController.destroy(); 87 } 88 } 89