[SF] Send NotifyExpectedPresentHint at the transaction time

BUG: 314199179
BUG: 315989692
BUG: 284845445

Test: atest NotifyExpectedPresentTest
Change-Id: Ief7fff69e8b92f0affd228b2bdcdc5009806f905
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index edba50b..0436c3c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2759,7 +2759,11 @@
     // TODO(b/255601557) Update frameInterval per display
     refreshArgs.frameInterval =
             mScheduler->getNextFrameInterval(pacesetterId, pacesetterTarget.expectedPresentTime());
-    refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
+    const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+    const auto scheduledFrameTimeOpt = scheduledFrameResultOpt
+            ? std::optional{scheduledFrameResultOpt->callbackTime}
+            : std::nullopt;
+    refreshArgs.scheduledFrameTime = scheduledFrameTimeOpt;
     refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
     // Store the present time just before calling to the composition engine so we could notify
     // the scheduler.
@@ -4258,7 +4262,8 @@
 
     auto hintStatus = data.hintStatus.load();
     if (!expectedPresentWithinTimeout) {
-        if (hintStatus != NotifyExpectedPresentHintStatus::Sent ||
+        if ((hintStatus != NotifyExpectedPresentHintStatus::Sent &&
+             hintStatus != NotifyExpectedPresentHintStatus::ScheduleOnTx) ||
             (timeoutOpt && timeoutOpt->ns() == 0)) {
             // Send the hint immediately if timeout, as the hint gets
             // delayed otherwise, as the frame is scheduled close
@@ -4267,11 +4272,16 @@
                         .compare_exchange_strong(hintStatus,
                                                  NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
                 scheduleNotifyExpectedPresentHint(displayId);
+                return;
             }
-            return;
         }
     }
 
+    if (hintStatus == NotifyExpectedPresentHintStatus::Sent &&
+        data.hintStatus.compare_exchange_strong(hintStatus,
+                                                NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
+        return;
+    }
     if (hintStatus != NotifyExpectedPresentHintStatus::Start) {
         return;
     }
@@ -4279,7 +4289,8 @@
     mScheduler->scheduleFrame();
 }
 
-void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId,
+                                                       VsyncId vsyncId) {
     auto itr = mNotifyExpectedPresentMap.find(displayId);
     if (itr == mNotifyExpectedPresentMap.end()) {
         return;
@@ -4288,10 +4299,30 @@
     const char* const whence = __func__;
     const auto sendHint = [=, this]() {
         auto& data = mNotifyExpectedPresentMap.at(displayId);
-        data.hintStatus.store(NotifyExpectedPresentHintStatus::Sent);
-        const auto status =
-                getHwComposer().notifyExpectedPresent(displayId, data.lastExpectedPresentTimestamp,
-                                                      data.lastFrameInterval);
+        TimePoint expectedPresentTime = data.lastExpectedPresentTimestamp;
+        if (ftl::to_underlying(vsyncId) != FrameTimelineInfo::INVALID_VSYNC_ID) {
+            const auto predictionOpt = mFrameTimeline->getTokenManager()->getPredictionsForToken(
+                    ftl::to_underlying(vsyncId));
+            const auto expectedPresentTimeOnPredictor = TimePoint::fromNs(
+                    predictionOpt ? predictionOpt->presentTime : expectedPresentTime.ns());
+            const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+            const auto expectedPresentTimeOnScheduler = scheduledFrameResultOpt.has_value()
+                    ? scheduledFrameResultOpt->vsyncTime
+                    : TimePoint::fromNs(0);
+            expectedPresentTime =
+                    std::max(expectedPresentTimeOnPredictor, expectedPresentTimeOnScheduler);
+        }
+
+        if (expectedPresentTime < TimePoint::now()) {
+            expectedPresentTime =
+                    mScheduler->getVsyncSchedule()->vsyncDeadlineAfter(TimePoint::now());
+            if (mScheduler->vsyncModulator().getVsyncConfig().sfWorkDuration >
+                mScheduler->getVsyncSchedule(displayId)->period()) {
+                expectedPresentTime += mScheduler->getVsyncSchedule(displayId)->period();
+            }
+        }
+        const auto status = getHwComposer().notifyExpectedPresent(displayId, expectedPresentTime,
+                                                                  data.lastFrameInterval);
         if (status != NO_ERROR) {
             ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, whence,
                   displayId.value);
@@ -4309,7 +4340,11 @@
             }
         }));
     }
-    sendHint();
+    auto scheduleHintOnPresent = NotifyExpectedPresentHintStatus::ScheduleOnPresent;
+    if (itr->second.hintStatus.compare_exchange_strong(scheduleHintOnPresent,
+                                                       NotifyExpectedPresentHintStatus::Sent)) {
+        sendHint();
+    }
 }
 
 void SurfaceFlinger::sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
@@ -5112,6 +5147,11 @@
 
     const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
     mTransactionHandler.queueTransaction(std::move(state));
+    for (const auto& [displayId, data] : mNotifyExpectedPresentMap) {
+        if (data.hintStatus.load() == NotifyExpectedPresentHintStatus::ScheduleOnTx) {
+            scheduleNotifyExpectedPresentHint(displayId, VsyncId{frameTimelineInfo.vsyncId});
+        }
+    }
     setTransactionFlags(eTransactionFlushNeeded, schedule, applyToken, frameHint);
     return NO_ERROR;
 }
@@ -8820,7 +8860,11 @@
         return;
     }
 
-    mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime());
+    const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+    const auto scheduleFrameTimeOpt = scheduledFrameResultOpt
+            ? std::optional{scheduledFrameResultOpt->callbackTime}
+            : std::nullopt;
+    mRegionSamplingThread->onCompositionComplete(scheduleFrameTimeOpt);
 }
 
 void SurfaceFlinger::onActiveDisplaySizeChanged(const DisplayDevice& activeDisplay) {