SF: introduce debug.sf.hwc.min.duration

debug.sf.hwc.min.duration can be set for specific devices to
indicate the shortest duration hwc will take to present a frame.
This value is used by SurfaceFlinger to calculate the
earlistPresentTime used for preventing an early present.

Bug: 190842189
Bug: 188854955
Test: SF unit tests
Test: run TouchLatency with debug.sf.hwc.min.duration set to a value
Change-Id: I8ffe92e5e6b355892c6bb073229f417fb0e9588c
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
index cb57aea..43e0297 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
@@ -59,7 +59,7 @@
 }
 
 void VsyncConfiguration::dump(std::string& result) const {
-    const auto [early, earlyGpu, late] = getCurrentConfigs();
+    const auto [early, earlyGpu, late, hwcMinWorkDuration] = getCurrentConfigs();
     using base::StringAppendF;
     StringAppendF(&result,
                   "           app phase:    %9" PRId64 " ns\t         SF phase:    %9" PRId64
@@ -70,7 +70,8 @@
                   "     early app duration: %9lld ns\t   early SF duration: %9lld ns\n"
                   "  GL early app phase:    %9" PRId64 " ns\tGL early SF phase:    %9" PRId64
                   " ns\n"
-                  "  GL early app duration: %9lld ns\tGL early SF duration: %9lld ns\n",
+                  "  GL early app duration: %9lld ns\tGL early SF duration: %9lld ns\n"
+                  "       HWC min duration: %9lld ns\n",
                   late.appOffset, late.sfOffset,
 
                   late.appWorkDuration.count(), late.sfWorkDuration.count(),
@@ -81,7 +82,9 @@
 
                   earlyGpu.appOffset, earlyGpu.sfOffset,
 
-                  earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count());
+                  earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count(),
+
+                  hwcMinWorkDuration.count());
 }
 
 PhaseOffsets::PhaseOffsets(Fps currentRefreshRate)
@@ -103,7 +106,8 @@
                      // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
                      // vsync.
                      getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
-                             .value_or(std::numeric_limits<nsecs_t>::max())) {}
+                             .value_or(std::numeric_limits<nsecs_t>::max()),
+                     getProperty("debug.sf.hwc.min.duration").value_or(0)) {}
 
 PhaseOffsets::PhaseOffsets(Fps currentFps, nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
                            std::optional<nsecs_t> earlySfOffsetNs,
@@ -115,7 +119,7 @@
                            std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
                            std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
                            std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
-                           nsecs_t thresholdForNextVsync)
+                           nsecs_t thresholdForNextVsync, nsecs_t hwcMinWorkDuration)
       : VsyncConfiguration(currentFps),
         mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
         mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
@@ -129,7 +133,8 @@
         mHighFpsEarlyGpuSfOffsetNs(highFpsEarlyGpuSfOffsetNs),
         mHighFpsEarlyAppOffsetNs(highFpsEarlyAppOffsetNs),
         mHighFpsEarlyGpuAppOffsetNs(highFpsEarlyGpuAppOffsetNs),
-        mThresholdForNextVsync(thresholdForNextVsync) {}
+        mThresholdForNextVsync(thresholdForNextVsync),
+        mHwcMinWorkDuration(hwcMinWorkDuration) {}
 
 PhaseOffsets::VsyncConfigSet PhaseOffsets::constructOffsets(nsecs_t vsyncDuration) const {
     if (vsyncDuration < std::chrono::nanoseconds(15ms).count()) {
@@ -189,6 +194,7 @@
                      .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
                      .appWorkDuration =
                              appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration)},
+            .hwcMinWorkDuration = std::chrono::nanoseconds(mHwcMinWorkDuration),
     };
 }
 
@@ -234,6 +240,7 @@
                             .appWorkDuration =
                                     appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration),
                     },
+            .hwcMinWorkDuration = std::chrono::nanoseconds(mHwcMinWorkDuration),
     };
 }
 
@@ -342,6 +349,7 @@
                             .sfWorkDuration = sfDuration,
                             .appWorkDuration = appDuration,
                     },
+            .hwcMinWorkDuration = std::chrono::nanoseconds(mHwcMinWorkDuration),
     };
 }
 
@@ -351,19 +359,22 @@
                      getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
                      getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
                      getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
-                     getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
+                     getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration),
+                     getProperty("debug.sf.hwc.min.duration").value_or(0)) {
     validateSysprops();
 }
 
 WorkDuration::WorkDuration(Fps currentRefreshRate, nsecs_t sfDuration, nsecs_t appDuration,
                            nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
-                           nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration)
+                           nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration,
+                           nsecs_t hwcMinWorkDuration)
       : VsyncConfiguration(currentRefreshRate),
         mSfDuration(sfDuration),
         mAppDuration(appDuration),
         mSfEarlyDuration(sfEarlyDuration),
         mAppEarlyDuration(appEarlyDuration),
         mSfEarlyGpuDuration(sfEarlyGpuDuration),
-        mAppEarlyGpuDuration(appEarlyGpuDuration) {}
+        mAppEarlyGpuDuration(appEarlyGpuDuration),
+        mHwcMinWorkDuration(hwcMinWorkDuration) {}
 
 } // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
index d9d206d..3e53b3f 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
@@ -111,7 +111,8 @@
                  nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
                  std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
                  std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
-                 std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync);
+                 std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync,
+                 nsecs_t hwcMinWorkDuration);
 
 private:
     VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const override;
@@ -134,6 +135,7 @@
     const std::optional<nsecs_t> mHighFpsEarlyGpuAppOffsetNs;
 
     const nsecs_t mThresholdForNextVsync;
+    const nsecs_t mHwcMinWorkDuration;
 };
 
 /*
@@ -148,7 +150,8 @@
 protected:
     // Used for unit tests
     WorkDuration(Fps currentFps, nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
-                 nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration);
+                 nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration,
+                 nsecs_t hwcMinWorkDuration);
 
 private:
     VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const override;
@@ -161,6 +164,8 @@
 
     const nsecs_t mSfEarlyGpuDuration;
     const nsecs_t mAppEarlyGpuDuration;
+
+    const nsecs_t mHwcMinWorkDuration;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index fcde279..9410768 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -69,9 +69,12 @@
         VsyncConfig early;    // Used for early transactions, and during refresh rate change.
         VsyncConfig earlyGpu; // Used during GPU composition.
         VsyncConfig late;     // Default.
+        std::chrono::nanoseconds hwcMinWorkDuration; // Used for calculating the
+                                                     // earliest present time
 
         bool operator==(const VsyncConfigSet& other) const {
-            return early == other.early && earlyGpu == other.earlyGpu && late == other.late;
+            return early == other.early && earlyGpu == other.earlyGpu && late == other.late &&
+                    hwcMinWorkDuration == other.hwcMinWorkDuration;
         }
 
         bool operator!=(const VsyncConfigSet& other) const { return !(*this == other); }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c1d28b1..73a5a57 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2066,7 +2066,9 @@
                 std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
     }
 
-    refreshArgs.earliestPresentTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime);
+    const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime);
+    const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
+    refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
     refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate();
 
     mGeometryInvalid = false;
diff --git a/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h b/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
index e890a62..f6f3c07 100644
--- a/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
+++ b/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
@@ -34,7 +34,8 @@
                 {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
                  FAKE_DURATION_OFFSET_NS},
                 {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
-                 FAKE_DURATION_OFFSET_NS}};
+                 FAKE_DURATION_OFFSET_NS},
+                FAKE_DURATION_OFFSET_NS};
     }
 
     void reset() override {}
diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
index bb7578d..41a4d30 100644
--- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
@@ -34,16 +34,18 @@
 public:
     TestableWorkDuration(Fps currentFps, nsecs_t sfDuration, nsecs_t appDuration,
                          nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
-                         nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration)
+                         nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration,
+                         nsecs_t hwcMinWorkDuration)
           : impl::WorkDuration(currentFps, sfDuration, appDuration, sfEarlyDuration,
-                               appEarlyDuration, sfEarlyGlDuration, appEarlyGlDuration) {}
+                               appEarlyDuration, sfEarlyGlDuration, appEarlyGlDuration,
+                               hwcMinWorkDuration) {}
 };
 
 class WorkDurationTest : public testing::Test {
 protected:
     WorkDurationTest()
           : mWorkDuration(Fps(60.0f), 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
-                          21'000'000) {}
+                          21'000'000, 1234) {}
 
     ~WorkDurationTest() = default;
 
@@ -104,7 +106,7 @@
 }
 
 TEST_F(WorkDurationTest, getConfigsForRefreshRate_DefaultOffsets) {
-    TestableWorkDuration phaseOffsetsWithDefaultValues(Fps(60.0f), -1, -1, -1, -1, -1, -1);
+    TestableWorkDuration phaseOffsetsWithDefaultValues(Fps(60.0f), -1, -1, -1, -1, -1, -1, 0);
 
     auto validateOffsets = [](const auto& offsets, std::chrono::nanoseconds vsyncPeriod) {
         EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
@@ -124,6 +126,8 @@
 
         EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, vsyncPeriod - 1'000'000ns);
         EXPECT_EQ(offsets.earlyGpu.appWorkDuration, vsyncPeriod);
+
+        EXPECT_EQ(offsets.hwcMinWorkDuration, 0ns);
     };
 
     const auto testForRefreshRate = [&](Fps refreshRate) {
@@ -160,6 +164,10 @@
     EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 21'000'000ns);
 }
 
+TEST_F(WorkDurationTest, minHwcWorkDuration) {
+    EXPECT_EQ(mWorkDuration.getCurrentConfigs().hwcMinWorkDuration, 1234ns);
+}
+
 class TestablePhaseOffsets : public impl::PhaseOffsets {
 public:
     TestablePhaseOffsets(nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
@@ -172,13 +180,14 @@
                          std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
                          std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
                          std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
-                         nsecs_t thresholdForNextVsync)
+                         nsecs_t thresholdForNextVsync, nsecs_t hwcMinWorkDuration)
           : impl::PhaseOffsets(Fps(60.0f), vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs,
                                earlySfOffsetNs, earlyGpuSfOffsetNs, earlyAppOffsetNs,
                                earlyGpuAppOffsetNs, highFpsVsyncPhaseOffsetNs,
                                highFpsSfVSyncPhaseOffsetNs, highFpsEarlySfOffsetNs,
                                highFpsEarlyGpuSfOffsetNs, highFpsEarlyAppOffsetNs,
-                               highFpsEarlyGpuAppOffsetNs, thresholdForNextVsync) {}
+                               highFpsEarlyGpuAppOffsetNs, thresholdForNextVsync,
+                               hwcMinWorkDuration) {}
 };
 
 class PhaseOffsetsTest : public testing::Test {
@@ -186,9 +195,9 @@
     PhaseOffsetsTest() = default;
     ~PhaseOffsetsTest() = default;
 
-    TestablePhaseOffsets mPhaseOffsets{2'000'000, 6'000'000, 7'000'000, 8'000'000, 3'000'000,
-                                       4'000'000, 2'000'000, 1'000'000, 2'000'000, 3'000'000,
-                                       3'000'000, 4'000'000, 10'000'000};
+    TestablePhaseOffsets mPhaseOffsets{2'000'000, 6'000'000, 7'000'000,  8'000'000, 3'000'000,
+                                       4'000'000, 2'000'000, 1'000'000,  2'000'000, 3'000'000,
+                                       3'000'000, 4'000'000, 10'000'000, 1234};
 };
 
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_unknownRefreshRate) {
@@ -258,8 +267,8 @@
 }
 
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_60Hz) {
-    TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {},        2'000'000,
-                                      1'000'000, {},        {}, {}, {}, 10'000'000};
+    TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {},         2'000'000,
+                                      1'000'000, {},        {}, {}, {}, 10'000'000, 1234};
     auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(60.0f));
 
     EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
@@ -282,8 +291,8 @@
 }
 
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_90Hz) {
-    TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {},        2'000'000,
-                                      1'000'000, {},        {}, {}, {}, 10'000'000};
+    TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {},         2'000'000,
+                                      1'000'000, {},        {}, {}, {}, 10'000'000, 1234};
     auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(90.0f));
 
     EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
@@ -305,4 +314,10 @@
     EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 21'222'222ns);
 }
 
+TEST_F(PhaseOffsetsTest, minHwcWorkDuration) {
+    TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {},         2'000'000,
+                                      1'000'000, {},        {}, {}, {}, 10'000'000, 1234};
+    EXPECT_EQ(phaseOffsets.getCurrentConfigs().hwcMinWorkDuration, 1234ns);
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
index 17648d5..60952bf 100644
--- a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
@@ -35,6 +35,7 @@
         APP_OFFSET_EARLY_GPU,
         SF_DURATION_EARLY_GPU,
         APP_DURATION_EARLY_GPU,
+        HWC_MIN_WORK_DURATION,
     };
 
     static VsyncModulator::TimePoint Now() {
@@ -57,7 +58,8 @@
                                             nanos(SF_DURATION_EARLY_GPU),
                                             nanos(APP_DURATION_EARLY_GPU)};
 
-    const VsyncModulator::VsyncConfigSet mOffsets = {kEarly, kEarlyGpu, kLate};
+    const VsyncModulator::VsyncConfigSet mOffsets = {kEarly, kEarlyGpu, kLate,
+                                                     nanos(HWC_MIN_WORK_DURATION)};
     VsyncModulator mVsyncModulator{mOffsets, Now};
 
     void SetUp() override { EXPECT_EQ(kLate, mVsyncModulator.setVsyncConfigSet(mOffsets)); }