SurfaceFlinger: refresh rate calculation when no timestamps

Frames without presentation timestamp should be excluded from refresh
rate calculation. This changes skips these frames instead of just
declaring refresh rate unknown. This impacts scenarios that we get few
frames without presentation timestamps where the majority does include
them.

Bug: 155710271
Test: Facebook feed videos
Change-Id: Id79f4d6cb87b2fd6fb787fab2d863f50be99cac5
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index bf1fb88..44b4264 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -111,21 +111,28 @@
 
     // Calculate the refresh rate by finding the average delta between frames
     nsecs_t totalPresentTimeDeltas = 0;
+    int numFrames = 0;
     for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
         // If there are no presentation timestamp provided we can't calculate the refresh rate
         if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
-            return std::nullopt;
+            continue;
         }
 
         totalPresentTimeDeltas +=
                 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
+        numFrames++;
     }
-    const float averageFrameTime =
-            static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
+    if (numFrames == 0) {
+        return std::nullopt;
+    }
+    const float averageFrameTime = static_cast<float>(totalPresentTimeDeltas) / numFrames;
 
     // Now once we calculated the refresh rate we need to make sure that all the frames we captured
     // are evenly distributed and we don't calculate the average across some burst of frames.
     for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+        if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
+            continue;
+        }
         const nsecs_t presentTimeDeltas =
                 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
         if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 6fca673..15207c9 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -512,5 +512,46 @@
     EXPECT_EQ(1, frequentLayerCount(time));
 }
 
+TEST_F(LayerHistoryTestV2, calculateRefreshRate30Hz) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    const nsecs_t frameTime = 33'333'333;
+
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        time += frameTime;
+        history().record(layer.get(), time, time);
+    }
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(30.f, history().summarize(time)[0].desiredRefreshRate);
+}
+
+TEST_F(LayerHistoryTestV2, calculateRefreshRate30HzSkipTimestamp) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    const nsecs_t frameTime = 33'333'333;
+
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        time += frameTime;
+        const auto timestamp = (i == PRESENT_TIME_HISTORY_SIZE / 2) ? 0 : time;
+        history().record(layer.get(), timestamp, time);
+    }
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(30.f, history().summarize(time)[0].desiredRefreshRate);
+}
+
 } // namespace
 } // namespace android::scheduler