[SF] Adds notifyExpectedPresent call for timeoutNs

Update notifyExpectedPresent to notifyExpectedPresentIfRequired

BUG: 296636253
BUG: 284845445
Test: atest HWComposerTest &&
 libsurfaceflinger_unittest
Change-Id: Ibb2b70cd6073be7c0c2be0507b47e6f5732a9303
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index facb808..6807c8e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -147,7 +147,8 @@
     MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&,
                 getOverlaySupport, (), (const, override));
     MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool));
-    MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, nsecs_t, int32_t));
+    MOCK_METHOD(status_t, notifyExpectedPresentIfRequired,
+                (PhysicalDisplayId, nsecs_t, int32_t, int32_t));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d6ef203..fb6089d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -31,6 +31,7 @@
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <ftl/concat.h>
+#include <gui/TraceUtils.h>
 #include <log/log.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
@@ -484,6 +485,7 @@
     }();
 
     displayData.validateWasSkipped = false;
+    displayData.lastExpectedPresentTimestamp = expectedPresentTime;
     if (canSkipValidate) {
         sp<Fence> outPresentFence;
         uint32_t state = UINT32_MAX;
@@ -876,12 +878,23 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::notifyExpectedPresent(PhysicalDisplayId displayId, nsecs_t expectedPresentTime,
-                                           int32_t frameIntervalNs) {
-    ATRACE_CALL();
+status_t HWComposer::notifyExpectedPresentIfRequired(PhysicalDisplayId displayId,
+                                                     nsecs_t expectedPresentTime,
+                                                     int32_t frameIntervalNs, int32_t timeoutNs) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
-    const auto error = mComposer->notifyExpectedPresent(mDisplayData[displayId].hwcDisplay->getId(),
+
+    auto& displayData = mDisplayData[displayId];
+    if (expectedPresentTime >= displayData.lastExpectedPresentTimestamp &&
+        expectedPresentTime < displayData.lastExpectedPresentTimestamp + timeoutNs) {
+        return NO_ERROR;
+    }
+
+    displayData.lastExpectedPresentTimestamp = expectedPresentTime;
+    ATRACE_FORMAT("%s ExpectedPresentTime %" PRId64 " frameIntervalNs %d", __func__,
+                  expectedPresentTime, frameIntervalNs);
+    const auto error = mComposer->notifyExpectedPresent(displayData.hwcDisplay->getId(),
                                                         expectedPresentTime, frameIntervalNs);
+
     if (error != hal::Error::NONE) {
         ALOGE("Error in notifyExpectedPresent call %s", to_string(error).c_str());
         return INVALID_OPERATION;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index e9dc4de..726a8ea 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -60,6 +60,7 @@
 struct DisplayedFrameStats;
 class GraphicBuffer;
 class TestableSurfaceFlinger;
+struct HWComposerTest;
 struct CompositionInfo;
 
 namespace Hwc2 {
@@ -300,8 +301,9 @@
             aidl::android::hardware::graphics::common::HdrConversionStrategy,
             aidl::android::hardware::graphics::common::Hdr*) = 0;
     virtual status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) = 0;
-    virtual status_t notifyExpectedPresent(PhysicalDisplayId, nsecs_t expectedPresentTime,
-                                           int32_t frameIntervalNs) = 0;
+    virtual status_t notifyExpectedPresentIfRequired(PhysicalDisplayId, nsecs_t expectedPresentTime,
+                                                     int32_t frameIntervalNs,
+                                                     int32_t timeoutNs) = 0;
 };
 
 static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs,
@@ -460,8 +462,8 @@
             aidl::android::hardware::graphics::common::HdrConversionStrategy,
             aidl::android::hardware::graphics::common::Hdr*) override;
     status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) override;
-    status_t notifyExpectedPresent(PhysicalDisplayId, nsecs_t expectedPresentTime,
-                                   int32_t frameIntervalNs) override;
+    status_t notifyExpectedPresentIfRequired(PhysicalDisplayId, nsecs_t expectedPresentTime,
+                                             int32_t frameIntervalNs, int32_t timeoutNs) override;
 
     // for debugging ----------------------------------------------------------
     void dump(std::string& out) const override;
@@ -487,6 +489,7 @@
 private:
     // For unit tests
     friend TestableSurfaceFlinger;
+    friend HWComposerTest;
 
     struct DisplayData {
         std::unique_ptr<HWC2::Display> hwcDisplay;
@@ -494,6 +497,8 @@
         sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
         nsecs_t lastPresentTimestamp = 0;
 
+        nsecs_t lastExpectedPresentTimestamp = 0;
+
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
 
         bool validateWasSkipped;
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 8a45f17..4f545a9 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -32,6 +32,7 @@
 
 #include <gui/LayerMetadata.h>
 #include <log/log.h>
+#include <chrono>
 
 #include "DisplayHardware/DisplayMode.h"
 #include "DisplayHardware/HWComposer.h"
@@ -44,11 +45,11 @@
 #pragma clang diagnostic pop // ignored "-Wconversion"
 
 namespace android {
-namespace {
 
 namespace V2_1 = hardware::graphics::composer::V2_1;
 namespace V2_4 = hardware::graphics::composer::V2_4;
 namespace aidl = aidl::android::hardware::graphics::composer3;
+using namespace std::chrono_literals;
 
 using Hwc2::Config;
 
@@ -77,6 +78,12 @@
         EXPECT_CALL(*mHal, setVsyncEnabled(hwcDisplayId, Hwc2::IComposerClient::Vsync::DISABLE));
         EXPECT_CALL(*mHal, onHotplugConnect(hwcDisplayId));
     }
+
+    void setDisplayData(HalDisplayId displayId, nsecs_t lastExpectedPresentTimestamp) {
+        ASSERT_TRUE(mHwc.mDisplayData.find(displayId) != mHwc.mDisplayData.end());
+        auto& displayData = mHwc.mDisplayData.at(displayId);
+        displayData.lastExpectedPresentTimestamp = lastExpectedPresentTimestamp;
+    }
 };
 
 TEST_F(HWComposerTest, isHeadless) {
@@ -227,12 +234,19 @@
         constexpr int32_t kHeight = 720;
         constexpr int32_t kConfigGroup = 1;
         constexpr int32_t kVsyncPeriod = 16666667;
-        hal::DisplayConfiguration displayConfiguration;
-        displayConfiguration.configId = kConfigId;
-        displayConfiguration.configGroup = kConfigGroup;
-        displayConfiguration.height = kHeight;
-        displayConfiguration.width = kWidth;
-        displayConfiguration.vsyncPeriod = kVsyncPeriod;
+        const hal::VrrConfig vrrConfig =
+                hal::VrrConfig{.minFrameIntervalNs = static_cast<Fps>(120_Hz).getPeriodNsecs(),
+                               .notifyExpectedPresentConfig = hal::VrrConfig::
+                                       NotifyExpectedPresentConfig{.notifyExpectedPresentHeadsUpNs =
+                                                                           ms2ns(30),
+                                                                   .notifyExpectedPresentTimeoutNs =
+                                                                           ms2ns(30)}};
+        hal::DisplayConfiguration displayConfiguration{.configId = kConfigId,
+                                                       .width = kWidth,
+                                                       .height = kHeight,
+                                                       .configGroup = kConfigGroup,
+                                                       .vsyncPeriod = kVsyncPeriod,
+                                                       .vrrConfig = vrrConfig};
 
         EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _))
                 .WillOnce(DoAll(SetArgPointee<2>(std::vector<hal::DisplayConfiguration>{
@@ -247,6 +261,7 @@
         EXPECT_EQ(modes.front().height, kHeight);
         EXPECT_EQ(modes.front().configGroup, kConfigGroup);
         EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
+        EXPECT_EQ(modes.front().vrrConfig, vrrConfig);
         EXPECT_EQ(modes.front().dpiX, -1);
         EXPECT_EQ(modes.front().dpiY, -1);
 
@@ -266,6 +281,7 @@
         EXPECT_EQ(modes.front().height, kHeight);
         EXPECT_EQ(modes.front().configGroup, kConfigGroup);
         EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
+        EXPECT_EQ(modes.front().vrrConfig, vrrConfig);
         EXPECT_EQ(modes.front().dpiX, kDpi);
         EXPECT_EQ(modes.front().dpiY, kDpi);
     }
@@ -299,6 +315,55 @@
     EXPECT_FALSE(displayIdOpt);
 }
 
+TEST_F(HWComposerTest, notifyExpectedPresentTimeout) {
+    constexpr hal::HWDisplayId kHwcDisplayId = 2;
+    expectHotplugConnect(kHwcDisplayId);
+    const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED);
+    ASSERT_TRUE(info);
+
+    auto expectedPresentTime = systemTime() + ms2ns(10);
+    const int32_t frameIntervalNs = static_cast<Fps>(60_Hz).getPeriodNsecs();
+    static constexpr nsecs_t kTimeoutNs = ms2ns(30);
+
+    ASSERT_NO_FATAL_FAILURE(setDisplayData(info->id, /* lastExpectedPresentTimestamp= */ 0));
+
+    {
+        // Very first ExpectedPresent after idle, no previous timestamp
+        EXPECT_CALL(*mHal,
+                    notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs))
+                .WillOnce(Return(HalError::NONE));
+        mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs,
+                                             kTimeoutNs);
+    }
+    {
+        // ExpectedPresent is after the timeoutNs
+        expectedPresentTime += ms2ns(50);
+        EXPECT_CALL(*mHal,
+                    notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs))
+                .WillOnce(Return(HalError::NONE));
+        mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs,
+                                             kTimeoutNs);
+    }
+    {
+        // ExpectedPresent is after the last reported ExpectedPresent.
+        expectedPresentTime += ms2ns(10);
+        EXPECT_CALL(*mHal, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+        mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs,
+                                             kTimeoutNs);
+    }
+    {
+        // ExpectedPresent is before the last reported ExpectedPresent but after the timeoutNs,
+        // representing we changed our decision and want to present earlier than previously
+        // reported.
+        expectedPresentTime -= ms2ns(20);
+        EXPECT_CALL(*mHal,
+                    notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs))
+                .WillOnce(Return(HalError::NONE));
+        mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs,
+                                             kTimeoutNs);
+    }
+}
+
 struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> {
     MOCK_METHOD2(onComposerHalHotplug, void(hal::HWDisplayId, hal::Connection));
     MOCK_METHOD1(onComposerHalRefresh, void(hal::HWDisplayId));
@@ -423,5 +488,4 @@
     EXPECT_EQ(hal::Error::UNSUPPORTED, result);
 }
 
-} // namespace
 } // namespace android