blob: b42536cb3f6c2a921f4d87f2c65a0db1b8da3289 [file] [log] [blame]
Chet Haase523d7a12021-01-07 15:41:42 -08001/*
2 * Copyright 2021 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 */
16package androidx.metrics.performance
17
Chet Haase523d7a12021-01-07 15:41:42 -080018import android.os.Handler
19import android.os.HandlerThread
20import android.view.FrameMetrics
21import android.view.View
22import android.view.Window
23import androidx.annotation.RequiresApi
24
25/**
26 * Subclass of JankStatsBaseImpl records frame timing data for API 24 and later,
27 * using FrameMetrics (which was introduced in API 24). Jank data is collected by
28 * setting a [Window.addOnFrameMetricsAvailableListener]
29 * on the Window associated with the Activity being tracked.
30 */
31@RequiresApi(24)
32internal open class JankStatsApi24Impl(
33 jankStats: JankStats,
Chet Haasea3e27592021-11-19 11:05:12 -080034 view: View,
35 private val window: Window
Chet Haase523d7a12021-01-07 15:41:42 -080036) : JankStatsApi22Impl(jankStats, view) {
37
Chet Haasea3e27592021-11-19 11:05:12 -080038 // Workaround for situation like b/206956036, where platform would sometimes send completely
39 // duplicate events through FrameMetrics. When that occurs, simply ignore the latest event
40 // that has the exact same start time.
41 var prevStart = 0L
42
Chet Haaseeca418b2022-01-12 12:44:19 -080043 // Used to avoid problems with data gathered before things are set up
44 var listenerAddedTime: Long = 0
45
Chet Haase523d7a12021-01-07 15:41:42 -080046 private val frameMetricsAvailableListener: Window.OnFrameMetricsAvailableListener =
47 Window.OnFrameMetricsAvailableListener { _, frameMetrics, _ ->
Chet Haase1d34c5d2021-09-24 17:00:50 -070048 val startTime = getFrameStartTime(frameMetrics)
Chet Haase523d7a12021-01-07 15:41:42 -080049 // ignore historical data gathered before we started listening
Chet Haasea3e27592021-11-19 11:05:12 -080050 if (startTime >= listenerAddedTime && startTime != prevStart) {
Chet Haase523d7a12021-01-07 15:41:42 -080051 val expectedDuration = getExpectedFrameDuration(frameMetrics) *
Chet Haase68900482021-10-12 10:21:30 -070052 jankStats.jankHeuristicMultiplier
Chet Haase523d7a12021-01-07 15:41:42 -080053 jankStats.logFrameData(
54 startTime,
Chet Haase1d34c5d2021-09-24 17:00:50 -070055 getFrameDuration(frameMetrics),
Chet Haase523d7a12021-01-07 15:41:42 -080056 expectedDuration.toLong()
57 )
Chet Haasea3e27592021-11-19 11:05:12 -080058 prevStart = startTime
Chet Haase523d7a12021-01-07 15:41:42 -080059 }
60 }
61
Chet Haase1d34c5d2021-09-24 17:00:50 -070062 internal open fun getFrameDuration(frameMetrics: FrameMetrics): Long {
63 return frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)
64 }
65
66 internal open fun getFrameStartTime(frameMetrics: FrameMetrics): Long {
67 return getFrameStartTime()
68 }
69
Chet Haase523d7a12021-01-07 15:41:42 -080070 open fun getExpectedFrameDuration(metrics: FrameMetrics): Long {
71 return getExpectedFrameDuration(decorViewRef.get())
72 }
73
Chet Haase523d7a12021-01-07 15:41:42 -080074 override fun setupFrameTimer(enable: Boolean) {
Chet Haasea3e27592021-11-19 11:05:12 -080075 window.let {
Chet Haase523d7a12021-01-07 15:41:42 -080076 if (enable) {
Chet Haaseeca418b2022-01-12 12:44:19 -080077 if (listenerAddedTime == 0L) {
78 if (frameMetricsHandler == null) {
79 val thread = HandlerThread("FrameMetricsAggregator")
80 thread.start()
81 frameMetricsHandler = Handler(thread.looper)
82 }
83 // Already added, no need to do it again
84 window.addOnFrameMetricsAvailableListener(
85 frameMetricsAvailableListener,
86 frameMetricsHandler
87 )
88 listenerAddedTime = System.nanoTime()
Chet Haase523d7a12021-01-07 15:41:42 -080089 }
Chet Haase523d7a12021-01-07 15:41:42 -080090 } else {
91 window.removeOnFrameMetricsAvailableListener(frameMetricsAvailableListener)
92 listenerAddedTime = 0
93 }
94 }
95 }
Chet Haaseeca418b2022-01-12 12:44:19 -080096
97 companion object {
98 private var frameMetricsHandler: Handler? = null
99 }
Chet Haase523d7a12021-01-07 15:41:42 -0800100}