SurfaceFlinger: fix early latching of buffers

Use the FrameTimeline::SurfaceFrame predicted present time
to avoid latching a buffer too early (i.e. before the time
SurfaceFlinger planned to latch this buffer when the app requested
a vsync callback).

Bug: 169901895
Test: expand notification shade and observe systrace
Change-Id: I823546992c89f88c0c29b839ce21c79ff1ffcfbd
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index fa75ffa..6561707 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -389,6 +389,20 @@
     mBufferInfo.mFrameLatencyNeeded = true;
 }
 
+bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const {
+    // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the
+    // vsync period. We can do this change as soon as ag/13100772 is merged.
+    constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms;
+
+    const auto presentTime = nextPredictedPresentTime();
+    if (std::abs(presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) {
+        return false;
+    }
+
+    return presentTime >= expectedPresentTime &&
+            presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
+}
+
 bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
                               nsecs_t expectedPresentTime) {
     ATRACE_CALL();
@@ -421,6 +435,12 @@
         return false;
     }
 
+    if (frameIsEarly(expectedPresentTime)) {
+        ATRACE_NAME("frameIsEarly()");
+        mFlinger->signalLayerUpdate();
+        return false;
+    }
+
     // If the head buffer's acquire fence hasn't signaled yet, return and
     // try again later
     if (!fenceHasSignaled()) {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 63dfe5f..5cd9a7c 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -224,6 +224,18 @@
     std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
 
     FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
+
+    // Returns true if the next frame is considered too early to present
+    // at the given expectedPresentTime
+    bool frameIsEarly(nsecs_t expectedPresentTime) const;
+
+    // Returns the predicted present time of the next frame if available or
+    // 0 otherwise.
+    virtual nsecs_t nextPredictedPresentTime() const = 0;
+
+    // The amount of time SF can delay a frame if it is considered early based
+    // on the VsyncModulator::VsyncConfig::appWorkDuration
+    static constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 56d8742..e8e31db 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -222,6 +222,21 @@
     return mQueuedFrames > 0;
 }
 
+nsecs_t BufferQueueLayer::nextPredictedPresentTime() const {
+    Mutex::Autolock lock(mQueueItemLock);
+    if (mQueueItems.empty()) {
+        return 0;
+    }
+
+    const auto& bufferData = mQueueItems[0];
+
+    if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) {
+        return 0;
+    }
+
+    return bufferData.surfaceFrame->getPredictions().presentTime;
+}
+
 status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
                                           nsecs_t expectedPresentTime) {
     // This boolean is used to make sure that SurfaceFlinger's shadow copy
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 3551026..2347d8c 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -116,6 +116,8 @@
     // Temporary - Used only for LEGACY camera mode.
     uint32_t getProducerStickyTransform() const;
 
+    nsecs_t nextPredictedPresentTime() const override;
+
     sp<BufferLayerConsumer> mConsumer;
     sp<IGraphicBufferProducer> mProducer;
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index df1472d..7ec7f36 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -601,6 +601,14 @@
     return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
 }
 
+nsecs_t BufferStateLayer::nextPredictedPresentTime() const {
+    if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
+        return 0;
+    }
+
+    return mSurfaceFrame->getPredictions().presentTime;
+}
+
 status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
                                           nsecs_t /*expectedPresentTime*/) {
     const State& s(getDrawingState());
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 734f647..6414e6b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -152,6 +152,8 @@
 
     bool bufferNeedsFiltering() const override;
 
+    nsecs_t nextPredictedPresentTime() const override;
+
     static const std::array<float, 16> IDENTITY_MATRIX;
 
     std::unique_ptr<renderengine::Image> mTextureImage;