Add refresh rate stats to TimeStats.

Bug: 122905821
Test: libsurfaceflinger_test
Test: dumpsys SurfaceFlinger --timestats -dump --proto
Change-Id: I99b38497f054f86bebba0813134f1c1eaf632b47
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 0f95cf9..f35758d 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <log/log.h>
@@ -24,6 +25,7 @@
 #include <utils/Vector.h>
 
 #include <random>
+#include <unordered_set>
 
 #include "TimeStats/TimeStats.h"
 
@@ -35,6 +37,10 @@
 namespace android {
 namespace {
 
+using testing::Contains;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
+
 // clang-format off
 #define FMT_PROTO          true
 #define FMT_STRING         false
@@ -127,7 +133,7 @@
     }
 
     std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
-    std::unique_ptr<TimeStats> mTimeStats = std::make_unique<TimeStats>();
+    std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
 };
 
 std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -371,6 +377,63 @@
     }
 }
 
+TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    uint32_t fpsOne = 30;
+    uint32_t fpsTwo = 90;
+    uint64_t millisOne = 5000;
+    uint64_t millisTwo = 7000;
+
+    mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
+    mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
+    SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
+    expectedConfigOne->set_fps(fpsOne);
+    expectedBucketOne.set_duration_millis(millisOne);
+
+    SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
+    SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
+    expectedConfigTwo->set_fps(fpsTwo);
+    expectedBucketTwo.set_duration_millis(millisTwo);
+
+    EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
+
+    std::unordered_set<uint32_t> seen_fps;
+    for (const auto& bucket : globalProto.display_config_stats()) {
+        seen_fps.emplace(bucket.config().fps());
+        if (fpsOne == bucket.config().fps()) {
+            EXPECT_EQ(millisOne, bucket.duration_millis());
+        } else if (fpsTwo == bucket.config().fps()) {
+            EXPECT_EQ(millisTwo, bucket.duration_millis());
+        } else {
+            FAIL() << "Unknown fps: " << bucket.config().fps();
+        }
+    }
+    EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
+}
+
+TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    uint32_t fps = 30;
+    uint64_t millisOne = 5000;
+    uint64_t millisTwo = 7000;
+
+    mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
+    mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+    EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
+    EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
+    EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
+}
+
 TEST_F(TimeStatsTest, canRemoveTimeRecord) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
@@ -394,7 +457,7 @@
     uint64_t frameNumber = 1;
     nsecs_t ts = 1000000;
     insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
-    for (size_t i = 0; i < TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
+    for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
         frameNumber++;
         ts += 1000000;
         insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);