SurfaceFlinger: fix infrequent frames logic
While playing video in YouTube, the UI posts sometimes 2 buffers
very close to each other, but overall frame rate is very low (~fps).
Fix the infrequent logic to detect this scenario.
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest
Bug: 147516364
Change-Id: Ie821252f793a18bb8830ac6582b9d99ab8b1c8f6
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index b755798..b4365bf 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -82,14 +82,14 @@
}
}
- const auto numFrames = std::distance(it, mFrameTimes.end()) - 1;
- if (numFrames <= 0) {
+ const auto numFrames = std::distance(it, mFrameTimes.end());
+ if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) {
return false;
}
// Layer is considered frequent if the average frame rate is higher than the threshold
const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
- return (1e9f * numFrames) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
+ return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
}
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 959c256..37da76b 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -36,6 +36,7 @@
protected:
static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE;
static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS;
+ static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE;
static constexpr float LO_FPS = 30.f;
static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS);
@@ -451,5 +452,61 @@
EXPECT_EQ(0, frequentLayerCount(time));
}
+TEST_F(LayerHistoryTestV2, inactiveLayers) {
+ auto layer = createLayer();
+
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+
+ // the very first updates makes the layer frequent
+ for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+ history().record(layer.get(), time, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ }
+
+ // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
+ history().record(layer.get(), time, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // advance the time for the previous frame to be inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+
+ // Now event if we post a quick few frame we should stay infrequent
+ for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+ history().record(layer.get(), time, time);
+ time += HI_FPS_PERIOD;
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ }
+
+ // More quick frames will get us to frequent again
+ history().record(layer.get(), time, time);
+ time += HI_FPS_PERIOD;
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
} // namespace
} // namespace android::scheduler