| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.base.jank_tracker; |
| |
| import android.app.Activity; |
| import android.os.Build; |
| |
| /** |
| * Class for recording janky frame metrics for a specific Activity. |
| * |
| * It should be constructed when the activity is created, recording starts and stops automatically |
| * based on activity state. When the activity is being destroyed {@link #destroy()} should be called |
| * to clear the activity state observer. All methods should be called from the UI thread. |
| */ |
| public class JankTrackerImpl implements JankTracker { |
| // We use the DEADLINE field in the Android FrameMetrics which was added in S. |
| private static final boolean IS_TRACKING_ENABLED = |
| Build.VERSION.SDK_INT >= Build.VERSION_CODES.S; |
| |
| private JankTrackerStateController mController; |
| private JankReportingScheduler mReportingScheduler; |
| |
| /** |
| * Creates a new JankTracker instance tracking UI rendering of an activity. Metric recording |
| * starts when the activity starts, and it's paused when the activity stops. |
| */ |
| public JankTrackerImpl(Activity activity) { |
| FrameMetricsStore metricsStore = new FrameMetricsStore(); |
| if (!constructInternalPreController(new JankReportingScheduler(metricsStore))) return; |
| |
| constructInternalFinal( |
| new JankActivityTracker( |
| activity, new FrameMetricsListener(metricsStore), mReportingScheduler)); |
| } |
| |
| /** |
| * Creates a new JankTracker which allows the controller to determine when it should start and |
| * stop metric scenarios/collection. |
| */ |
| public JankTrackerImpl(JankTrackerStateController controller) { |
| if (!constructInternalPreController(controller.mReportingScheduler)) return; |
| constructInternalFinal(controller); |
| } |
| |
| private boolean constructInternalPreController(JankReportingScheduler scheduler) { |
| if (!IS_TRACKING_ENABLED) { |
| mReportingScheduler = null; |
| mController = null; |
| return false; |
| } |
| mReportingScheduler = scheduler; |
| return true; |
| } |
| |
| private void constructInternalFinal(JankTrackerStateController controller) { |
| mController = controller; |
| mController.initialize(); |
| } |
| |
| @Override |
| public void startTrackingScenario(@JankScenario int scenario) { |
| if (!IS_TRACKING_ENABLED) return; |
| |
| mReportingScheduler.startTrackingScenario(scenario); |
| } |
| |
| @Override |
| public void finishTrackingScenario(@JankScenario int scenario) { |
| finishTrackingScenario(scenario, -1); |
| } |
| |
| @Override |
| public void finishTrackingScenario(@JankScenario int scenario, long endScenarioTimeNs) { |
| if (!IS_TRACKING_ENABLED) return; |
| |
| mReportingScheduler.finishTrackingScenario(scenario, endScenarioTimeNs); |
| } |
| |
| /** Stops listening for Activity state changes. */ |
| @Override |
| public void destroy() { |
| if (!IS_TRACKING_ENABLED) return; |
| |
| mController.destroy(); |
| } |
| } |