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.VERSION_CODES; 9 10 import androidx.annotation.RequiresApi; 11 12 import org.chromium.base.ActivityState; 13 import org.chromium.base.ApplicationStatus; 14 import org.chromium.base.ApplicationStatus.ActivityStateListener; 15 import org.chromium.base.ThreadUtils.ThreadChecker; 16 import org.chromium.base.lifetime.DestroyChecker; 17 18 import java.lang.ref.WeakReference; 19 20 /** 21 * This class takes an Activity and attaches a FrameMetricsListener to it, in addition it controls 22 * periodic jank metric reporting and frame metric recording based on the Activity's lifecycle 23 * events. 24 */ 25 @RequiresApi(api = VERSION_CODES.N) 26 class JankActivityTracker extends JankTrackerStateController implements ActivityStateListener { 27 private final ThreadChecker mThreadChecker = new ThreadChecker(); 28 private final DestroyChecker mDestroyChecker = new DestroyChecker(); 29 30 private WeakReference<Activity> mActivityReference; 31 JankActivityTracker( Activity context, FrameMetricsListener listener, JankReportingScheduler reportingScheduler)32 JankActivityTracker( 33 Activity context, 34 FrameMetricsListener listener, 35 JankReportingScheduler reportingScheduler) { 36 super(listener, reportingScheduler); 37 mActivityReference = new WeakReference<>(context); 38 } 39 40 @Override initialize()41 public void initialize() { 42 assertValidState(); 43 Activity activity = mActivityReference.get(); 44 if (activity != null) { 45 ApplicationStatus.registerStateListenerForActivity(this, activity); 46 @ActivityState int activityState = ApplicationStatus.getStateForActivity(activity); 47 onActivityStateChange(activity, activityState); 48 startMetricCollection(activity.getWindow()); 49 } 50 } 51 52 @Override destroy()53 public void destroy() { 54 mThreadChecker.assertOnValidThread(); 55 ApplicationStatus.unregisterActivityStateListener(this); 56 stopPeriodicReporting(); 57 Activity activity = mActivityReference.get(); 58 if (activity != null) { 59 stopMetricCollection(activity.getWindow()); 60 } 61 mDestroyChecker.destroy(); 62 } 63 assertValidState()64 private void assertValidState() { 65 mThreadChecker.assertOnValidThread(); 66 mDestroyChecker.checkNotDestroyed(); 67 } 68 69 @Override onActivityStateChange(Activity activity, @ActivityState int newState)70 public void onActivityStateChange(Activity activity, @ActivityState int newState) { 71 assertValidState(); 72 switch (newState) { 73 case ActivityState.STARTED: // Intentional fallthrough. 74 case ActivityState.RESUMED: 75 startPeriodicReporting(); 76 startMetricCollection(null); 77 break; 78 case ActivityState.PAUSED: 79 // This method can be called at any moment safely, we want to report metrics even 80 // when the activity is paused. 81 startPeriodicReporting(); 82 stopMetricCollection(null); 83 break; 84 case ActivityState.STOPPED: 85 stopPeriodicReporting(); 86 stopMetricCollection(null); 87 break; 88 } 89 } 90 } 91