Merge changes from topic "sf_maxAcquiredBufferCount" into sc-dev

* changes:
  SF: change acquired buffers based on the current refresh rate
  SF: increase the number of buffers for SurfaceView
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index b9a293f..52d3fa3 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -29,9 +29,10 @@
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
 #include <utils/Singleton.h>
-
 #include <utils/Trace.h>
 
+#include <private/gui/ComposerService.h>
+
 #include <chrono>
 
 using namespace std::chrono_literals;
@@ -158,6 +159,9 @@
     mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
     mBufferItemConsumer->setBlastBufferQueue(this);
 
+    ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
+    mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
+
     mTransformHint = mSurfaceControl->getTransformHint();
     mBufferItemConsumer->setTransformHint(mTransformHint);
     SurfaceComposerClient::Transaction()
@@ -302,18 +306,20 @@
 // So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
 // Otherwise, this is a no-op.
 static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, uint64_t graphicBufferId,
-                                       const sp<Fence>& releaseFence, uint32_t transformHint) {
+                                       const sp<Fence>& releaseFence, uint32_t transformHint,
+                                       uint32_t currentMaxAcquiredBufferCount) {
     sp<BLASTBufferQueue> blastBufferQueue = context.promote();
     ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s",
           graphicBufferId, blastBufferQueue ? "alive" : "dead");
     if (blastBufferQueue) {
-        blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint);
+        blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint,
+                                                currentMaxAcquiredBufferCount);
     }
 }
 
 void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId,
-                                             const sp<Fence>& releaseFence,
-                                             uint32_t transformHint) {
+                                             const sp<Fence>& releaseFence, uint32_t transformHint,
+                                             uint32_t currentMaxAcquiredBufferCount) {
     ATRACE_CALL();
     std::unique_lock _lock{mMutex};
     BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId);
@@ -324,15 +330,36 @@
         mBufferItemConsumer->setTransformHint(mTransformHint);
     }
 
-    auto it = mSubmitted.find(graphicBufferId);
-    if (it == mSubmitted.end()) {
-        BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64,
-                 graphicBufferId);
-        return;
+    // Calculate how many buffers we need to hold before we release them back
+    // to the buffer queue. This will prevent higher latency when we are running
+    // on a lower refresh rate than the max supported. We only do that for EGL
+    // clients as others don't care about latency
+    const bool isEGL = [&] {
+        const auto it = mSubmitted.find(graphicBufferId);
+        return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
+    }();
+
+    const auto numPendingBuffersToHold =
+            isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
+    mPendingRelease.emplace_back(ReleasedBuffer{graphicBufferId, releaseFence});
+
+    // Release all buffers that are beyond the ones that we need to hold
+    while (mPendingRelease.size() > numPendingBuffersToHold) {
+        const auto releaseBuffer = mPendingRelease.front();
+        mPendingRelease.pop_front();
+        auto it = mSubmitted.find(releaseBuffer.bufferId);
+        if (it == mSubmitted.end()) {
+            BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64,
+                     graphicBufferId);
+            return;
+        }
+
+        mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
+        mSubmitted.erase(it);
     }
 
-    mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
-    mSubmitted.erase(it);
+    ATRACE_INT("PendingRelease", mPendingRelease.size());
+
     mNumAcquired--;
     processNextBufferLocked(false /* useNextTransaction */);
     mCallbackCV.notify_all();
@@ -414,7 +441,8 @@
 
     auto releaseBufferCallback =
             std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
-                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
+                      std::placeholders::_4);
     t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback);
     t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
     t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
@@ -567,7 +595,7 @@
 // includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
 // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
 bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
-    int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1);
+    int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1);
     return mNumAcquired == maxAcquiredBuffers;
 }
 
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 71e18a9..0d7795e 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1215,16 +1215,17 @@
         return reply.readInt32();
     }
 
-    status_t getExtraBufferCount(int* extraBuffers) const override {
+    status_t getMaxAcquiredBufferCount(int* buffers) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        status_t err = remote()->transact(BnSurfaceComposer::GET_EXTRA_BUFFER_COUNT, data, &reply);
+        status_t err =
+                remote()->transact(BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
         if (err != NO_ERROR) {
-            ALOGE("getExtraBufferCount failed to read data:  %s (%d)", strerror(-err), err);
+            ALOGE("getMaxAcquiredBufferCount failed to read data:  %s (%d)", strerror(-err), err);
             return err;
         }
 
-        return reply.readInt32(extraBuffers);
+        return reply.readInt32(buffers);
     }
 };
 
@@ -2069,14 +2070,14 @@
             SAFE_PARCEL(reply->writeInt32, priority);
             return NO_ERROR;
         }
-        case GET_EXTRA_BUFFER_COUNT: {
+        case GET_MAX_ACQUIRED_BUFFER_COUNT: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int extraBuffers = 0;
-            int err = getExtraBufferCount(&extraBuffers);
+            int buffers = 0;
+            int err = getMaxAcquiredBufferCount(&buffers);
             if (err != NO_ERROR) {
                 return err;
             }
-            SAFE_PARCEL(reply->writeInt32, extraBuffers);
+            SAFE_PARCEL(reply->writeInt32, buffers);
             return NO_ERROR;
         }
         case OVERRIDE_HDR_TYPES: {
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 63d07ba..17499ec 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -119,6 +119,7 @@
         SAFE_PARCEL(output->writeBool, false);
     }
     SAFE_PARCEL(output->writeUint32, transformHint);
+    SAFE_PARCEL(output->writeUint32, currentMaxAcquiredBufferCount);
     SAFE_PARCEL(output->writeParcelable, eventStats);
     SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
     for (const auto& data : jankData) {
@@ -138,6 +139,7 @@
         SAFE_PARCEL(input->read, *previousReleaseFence);
     }
     SAFE_PARCEL(input->readUint32, &transformHint);
+    SAFE_PARCEL(input->readUint32, &currentMaxAcquiredBufferCount);
     SAFE_PARCEL(input->readParcelable, &eventStats);
 
     int32_t jankData_size = 0;
@@ -251,11 +253,13 @@
                                                                   stats);
     }
 
-    void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
-                         uint32_t transformHint) override {
+    void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence, uint32_t transformHint,
+                         uint32_t currentMaxAcquiredBufferCount) override {
         callRemoteAsync<decltype(
                 &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER,
-                graphicBufferId, releaseFence, transformHint);
+                                                                  graphicBufferId, releaseFence,
+                                                                  transformHint,
+                                                                  currentMaxAcquiredBufferCount);
     }
 };
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e117d11..821ec16 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1501,9 +1501,6 @@
     case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO:
         res = dispatchSetFrameTimelineInfo(args);
         break;
-    case NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT:
-        res = dispatchGetExtraBufferCount(args);
-        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1853,14 +1850,6 @@
     return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId});
 }
 
-int Surface::dispatchGetExtraBufferCount(va_list args) {
-    ATRACE_CALL();
-    auto extraBuffers = static_cast<int*>(va_arg(args, int*));
-
-    ALOGV("Surface::dispatchGetExtraBufferCount");
-    return getExtraBufferCount(extraBuffers);
-}
-
 bool Surface::transformToDisplayInverse() const {
     return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -2632,8 +2621,4 @@
     return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo);
 }
 
-status_t Surface::getExtraBufferCount(int* extraBuffers) const {
-    return composerService()->getExtraBufferCount(extraBuffers);
-}
-
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 660c5bd..c69435d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -328,7 +328,8 @@
                                  surfaceStats.previousReleaseFence
                                          ? surfaceStats.previousReleaseFence
                                          : Fence::NO_FENCE,
-                                 surfaceStats.transformHint);
+                                 surfaceStats.transformHint,
+                                 surfaceStats.currentMaxAcquiredBufferCount);
                     }
                 }
             }
@@ -364,9 +365,9 @@
     }
 }
 
-void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId,
-                                                   sp<Fence> releaseFence,
-                                                   uint32_t transformHint) {
+void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
+                                                   uint32_t transformHint,
+                                                   uint32_t currentMaxAcquiredBufferCount) {
     ReleaseBufferCallback callback;
     {
         std::scoped_lock<std::mutex> lock(mMutex);
@@ -376,7 +377,7 @@
         ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId);
         return;
     }
-    callback(graphicBufferId, releaseFence, transformHint);
+    callback(graphicBufferId, releaseFence, transformHint, currentMaxAcquiredBufferCount);
 }
 
 ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index d7c07b9..6529a4e 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -139,7 +139,7 @@
                                  ISurfaceComposerClient::eOpaque);
     mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
                                        flags, mHandle, {}, &ignore);
-    mBbq = new BLASTBufferQueue("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
+    mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
 
     // This surface is always consumed by SurfaceFlinger, so the
     // producerControlledByApp value doesn't matter; using false.
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 3ab1ee1..0981e76 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -90,7 +90,7 @@
     void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
             const std::vector<SurfaceControlStats>& stats);
     void releaseBufferCallback(uint64_t graphicBufferId, const sp<Fence>& releaseFence,
-                               uint32_t transformHint);
+                               uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
     void setNextTransaction(SurfaceComposerClient::Transaction *t);
     void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
     void setTransactionCompleteCallback(uint64_t frameNumber,
@@ -132,7 +132,7 @@
 
     // BufferQueue internally allows 1 more than
     // the max to be acquired
-    static const int MAX_ACQUIRED_BUFFERS = 1;
+    int32_t mMaxAcquiredBuffers = 1;
 
     int32_t mNumFrameAvailable GUARDED_BY(mMutex);
     int32_t mNumAcquired GUARDED_BY(mMutex);
@@ -141,6 +141,15 @@
     // buffer or the buffer has been presented and a new buffer is ready to be presented.
     std::unordered_map<uint64_t /* bufferId */, BufferItem> mSubmitted GUARDED_BY(mMutex);
 
+    // Keep a queue of the released buffers instead of immediately releasing
+    // the buffers back to the buffer queue. This would be controlled by SF
+    // setting the max acquired buffer count.
+    struct ReleasedBuffer {
+        uint64_t bufferId;
+        sp<Fence> releaseFence;
+    };
+    std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);
+
     ui::Size mSize GUARDED_BY(mMutex);
     ui::Size mRequestedSize GUARDED_BY(mMutex);
     int32_t mFormat GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 439d90a..2a3f6a4 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -537,22 +537,21 @@
     virtual int getGPUContextPriority() = 0;
 
     /**
-     * Gets the extra buffers a client would need to allocate if it passes
-     * the Choreographer#getVsyncId with its buffers.
-     *
-     * When Choreographer#getVsyncId is passed to SurfaceFlinger, it is used
-     * as an indication of when to latch the buffer. SurfaceFlinger will make
-     * sure that it will give the app at least the time configured as the
-     * 'appDuration' before trying to latch the buffer.
+     * Gets the number of buffers SurfaceFlinger would need acquire. This number
+     * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the
+     * client could allocate enough buffers to match SF expectations of the
+     * pipeline depth. SurfaceFlinger will make sure that it will give the app at
+     * least the time configured as the 'appDuration' before trying to latch
+     * the buffer.
      *
      * The total buffers needed for a given configuration is basically the
      * numbers of vsyncs a single buffer is used across the stack. For the default
      * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger
      * and 1 vsync by the display. The extra buffers are calculated as the
-     * number of additional buffers on top of the 3 buffers already allocated
-     * by the app.
+     * number of additional buffers on top of the 2 buffers already present
+     * in MIN_UNDEQUEUED_BUFFERS.
      */
-    virtual status_t getExtraBufferCount(int* extraBuffers) const = 0;
+    virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -615,7 +614,7 @@
         SET_FRAME_TIMELINE_INFO,
         ADD_TRANSACTION_TRACE_LISTENER,
         GET_GPU_CONTEXT_PRIORITY,
-        GET_EXTRA_BUFFER_COUNT,
+        GET_MAX_ACQUIRED_BUFFER_COUNT,
         GET_DYNAMIC_DISPLAY_INFO,
         ADD_FPS_LISTENER,
         REMOVE_FPS_LISTENER,
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 3bfeef1..d286c34 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -101,12 +101,14 @@
 
     SurfaceStats() = default;
     SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
-                 uint32_t hint, FrameEventHistoryStats frameEventStats,
-                 std::vector<JankData> jankData, uint64_t previousBufferId)
+                 uint32_t hint, uint32_t currentMaxAcquiredBuffersCount,
+                 FrameEventHistoryStats frameEventStats, std::vector<JankData> jankData,
+                 uint64_t previousBufferId)
           : surfaceControl(sc),
             acquireTime(time),
             previousReleaseFence(prevReleaseFence),
             transformHint(hint),
+            currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount),
             eventStats(frameEventStats),
             jankData(std::move(jankData)),
             previousBufferId(previousBufferId) {}
@@ -115,6 +117,7 @@
     nsecs_t acquireTime = -1;
     sp<Fence> previousReleaseFence;
     uint32_t transformHint = 0;
+    uint32_t currentMaxAcquiredBufferCount = 0;
     FrameEventHistoryStats eventStats;
     std::vector<JankData> jankData;
     uint64_t previousBufferId;
@@ -159,7 +162,8 @@
     virtual void onTransactionCompleted(ListenerStats stats) = 0;
 
     virtual void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
-                                 uint32_t transformHint) = 0;
+                                 uint32_t transformHint,
+                                 uint32_t currentMaxAcquiredBufferCount) = 0;
 };
 
 class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 48885eb..7e4143b 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -190,7 +190,6 @@
     virtual status_t setFrameRate(float frameRate, int8_t compatibility,
                                   int8_t changeFrameRateStrategy);
     virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
-    virtual status_t getExtraBufferCount(int* extraBuffers) const;
 
 protected:
     virtual ~Surface();
@@ -278,7 +277,6 @@
     int dispatchGetLastQueuedBuffer(va_list args);
     int dispatchGetLastQueuedBuffer2(va_list args);
     int dispatchSetFrameTimelineInfo(va_list args);
-    int dispatchGetExtraBufferCount(va_list args);
 
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 5aa132c..fa91bfa 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -83,7 +83,7 @@
                            const std::vector<SurfaceControlStats>& /*stats*/)>;
 using ReleaseBufferCallback =
         std::function<void(uint64_t /* graphicsBufferId */, const sp<Fence>& /*releaseFence*/,
-                           uint32_t transformHint)>;
+                           uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>;
 
 using SurfaceStatsCallback =
         std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
@@ -729,7 +729,7 @@
     // BnTransactionCompletedListener overrides
     void onTransactionCompleted(ListenerStats stats) override;
     void onReleaseBuffer(uint64_t /* graphicsBufferId */, sp<Fence> releaseFence,
-                         uint32_t transformHint) override;
+                         uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override;
 
 private:
     ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 5a5da97..06660b8 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -394,7 +394,11 @@
     setUpProducer(adapter, igbProducer);
 
     std::vector<std::pair<int, sp<Fence>>> allocated;
-    for (int i = 0; i < 3; i++) {
+    int minUndequeuedBuffers = 0;
+    ASSERT_EQ(OK, igbProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers));
+    const auto bufferCount = minUndequeuedBuffers + 2;
+
+    for (int i = 0; i < bufferCount; i++) {
         int slot;
         sp<Fence> fence;
         sp<GraphicBuffer> buf;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index b8d34c3..59b0c04 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -902,7 +902,7 @@
 
     int getGPUContextPriority() override { return 0; };
 
-    status_t getExtraBufferCount(int* /*extraBuffers*/) const override { return NO_ERROR; }
+    status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; }
 
 protected:
     IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 935eded..7f01135 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -256,8 +256,7 @@
     NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER          = 46,    /* private */
     NATIVE_WINDOW_SET_QUERY_INTERCEPTOR           = 47,    /* private */
     NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO         = 48,    /* private */
-    NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT          = 49,    /* private */
-    NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2         = 50,    /* private */
+    NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2         = 49,    /* private */
     // clang-format on
 };
 
@@ -1032,11 +1031,6 @@
                            frameTimelineVsyncId, inputEventId);
 }
 
-static inline int native_window_get_extra_buffer_count(
-    struct ANativeWindow* window, int* extraBuffers) {
-    return window->perform(window, NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT, extraBuffers);
-}
-
 // ------------------------------------------------------------------------------------------------
 // Candidates for APEX visibility
 // These functions are planned to be made stable for APEX modules, but have not
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 6213a8a..f8af908 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -45,12 +45,12 @@
 namespace {
 void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
                                const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence,
-                               uint32_t transformHint) {
+                               uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) {
     if (!listener) {
         return;
     }
     listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE,
-                              transformHint);
+                              transformHint, currentMaxAcquiredBufferCount);
 }
 } // namespace
 
@@ -76,7 +76,9 @@
     if (mBufferInfo.mBuffer != nullptr && !isClone()) {
         callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                   mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence,
-                                  mTransformHint);
+                                  mTransformHint,
+                                  mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+                                          mOwnerUid));
     }
 }
 
@@ -200,6 +202,8 @@
     for (const auto& handle : mDrawingState.callbackHandles) {
         handle->transformHint = mTransformHint;
         handle->dequeueReadyTime = dequeueReadyTime;
+        handle->currentMaxAcquiredBufferCount =
+                mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
     }
 
     // If there are multiple transactions in this frame, set the previous id on the earliest
@@ -430,9 +434,10 @@
             // dropped and we should decrement the pending buffer count and
             // call any release buffer callbacks if set.
             callReleaseBufferCallback(mCurrentState.releaseBufferListener,
-                                      mCurrentState.buffer->getBuffer(),
-                                      mCurrentState.acquireFence,
-                                      mTransformHint);
+                                      mCurrentState.buffer->getBuffer(), mCurrentState.acquireFence,
+                                      mTransformHint,
+                                      mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+                                              mOwnerUid));
             decrementPendingBufferCount();
             if (mCurrentState.bufferSurfaceFrameTX != nullptr) {
                 addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX);
@@ -952,7 +957,9 @@
         // call any release buffer callbacks if set.
         callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                   mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence,
-                                  mTransformHint);
+                                  mTransformHint,
+                                  mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+                                          mOwnerUid));
         decrementPendingBufferCount();
     }
 }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4b8cbfb..e0b3640 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -205,6 +205,10 @@
 }
 
 std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
+    if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+        return std::nullopt;
+    }
+
     std::lock_guard lock(mFrameRateOverridesMutex);
     {
         const auto iter = mFrameRateOverridesFromBackdoor.find(uid);
@@ -224,10 +228,6 @@
 }
 
 bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const {
-    if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
-        return true;
-    }
-
     const auto frameRate = getFrameRateOverride(uid);
     if (!frameRate.has_value()) {
         return true;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4fcec16..fddec1b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5247,7 +5247,7 @@
         case CAPTURE_DISPLAY:
         case SET_FRAME_TIMELINE_INFO:
         case GET_GPU_CONTEXT_PRIORITY:
-        case GET_EXTRA_BUFFER_COUNT: {
+        case GET_MAX_ACQUIRED_BUFFER_COUNT: {
             // This is not sensitive information, so should not require permission control.
             return OK;
         }
@@ -6800,25 +6800,38 @@
     return getRenderEngine().getContextPriority();
 }
 
-int SurfaceFlinger::calculateExtraBufferCount(Fps maxSupportedRefreshRate,
-                                              std::chrono::nanoseconds presentLatency) {
-    auto pipelineDepth = presentLatency.count() / maxSupportedRefreshRate.getPeriodNsecs();
-    if (presentLatency.count() % maxSupportedRefreshRate.getPeriodNsecs()) {
+int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate,
+                                                    std::chrono::nanoseconds presentLatency) {
+    auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs();
+    if (presentLatency.count() % refreshRate.getPeriodNsecs()) {
         pipelineDepth++;
     }
-    return std::max(0ll, pipelineDepth - 2);
+    return std::max(1ll, pipelineDepth - 1);
 }
 
-status_t SurfaceFlinger::getExtraBufferCount(int* extraBuffers) const {
+status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
     const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max;
-    const auto vsyncConfig =
-            mVsyncConfiguration->getConfigsForRefreshRate(maxSupportedRefreshRate).late;
-    const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration;
-
-    *extraBuffers = calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+    *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate);
     return NO_ERROR;
 }
 
+int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
+    const auto refreshRate = [&] {
+        const auto frameRateOverride = mScheduler->getFrameRateOverride(uid);
+        if (frameRateOverride.has_value()) {
+            return frameRateOverride.value();
+        }
+        return mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+    }();
+    return getMaxAcquiredBufferCountForRefreshRate(refreshRate);
+}
+
+int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const {
+    const auto vsyncConfig = mVsyncConfiguration->getConfigsForRefreshRate(refreshRate).late;
+    const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration;
+    return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
+}
+
 void SurfaceFlinger::TransactionState::traverseStatesWithBuffers(
         std::function<void(const layer_state_t&)> visitor) {
     for (const auto& state : states) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a3fa8d6..22d17eb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -708,7 +708,7 @@
 
     int getGPUContextPriority() override;
 
-    status_t getExtraBufferCount(int* extraBuffers) const override;
+    status_t getMaxAcquiredBufferCount(int* buffers) const override;
 
     // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
@@ -923,6 +923,8 @@
     size_t getMaxTextureSize() const;
     size_t getMaxViewportDims() const;
 
+    int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
+
     /*
      * Display and layer stack management
      */
@@ -1062,6 +1064,7 @@
 
     // Calculates the expected present time for this frame. For negative offsets, performs a
     // correction using the predicted vsync for the next frame instead.
+
     nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const;
 
     /*
@@ -1177,8 +1180,9 @@
     std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
             REQUIRES(mStateLock);
 
-    static int calculateExtraBufferCount(Fps maxSupportedRefreshRate,
-                                         std::chrono::nanoseconds presentLatency);
+    static int calculateMaxAcquiredBufferCount(Fps refreshRate,
+                                               std::chrono::nanoseconds presentLatency);
+    int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
 
     sp<StartPropertySetThread> mStartPropertySetThread;
     surfaceflinger::Factory& mFactory;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 4f4c02b..fdf16a7 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -235,8 +235,9 @@
                                           handle->dequeueReadyTime);
         transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
                                                     handle->previousReleaseFence,
-                                                    handle->transformHint, eventStats, jankData,
-                                                    handle->previousBufferId);
+                                                    handle->transformHint,
+                                                    handle->currentMaxAcquiredBufferCount,
+                                                    eventStats, jankData, handle->previousBufferId);
     }
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 184b151..444bec6 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -45,6 +45,7 @@
     nsecs_t acquireTime = -1;
     nsecs_t latchTime = -1;
     uint32_t transformHint = 0;
+    uint32_t currentMaxAcquiredBufferCount = 0;
     std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
     CompositorTiming compositorTiming;
     nsecs_t refreshStartTime = 0;
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index fb7d41c..5aa809d 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -30,7 +30,8 @@
 class ReleaseBufferCallbackHelper {
 public:
     static void function(void* callbackContext, uint64_t graphicsBufferId,
-                         const sp<Fence>& releaseFence) {
+                         const sp<Fence>& releaseFence,
+                         uint32_t /*currentMaxAcquiredBufferCount*/) {
         if (!callbackContext) {
             FAIL() << "failed to get callback context";
         }
@@ -66,7 +67,7 @@
 
     android::ReleaseBufferCallback getCallback() {
         return std::bind(function, static_cast<void*>(this) /* callbackContext */,
-                         std::placeholders::_1, std::placeholders::_2);
+                         std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
     }
 
     std::mutex mMutex;
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 423d0cc..f680d80 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -210,14 +210,14 @@
     EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
 }
 
-TEST_F(SchedulerTest, calculateExtraBufferCount) {
-    EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 30ms));
-    EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(90), 30ms));
-    EXPECT_EQ(2, mFlinger.calculateExtraBufferCount(Fps(120), 30ms));
+TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
+    EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 30ms));
+    EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(90), 30ms));
+    EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(Fps(120), 30ms));
 
-    EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(60), 40ms));
+    EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 40ms));
 
-    EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 10ms));
+    EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 10ms));
 }
 
 MATCHER(Is120Hz, "") {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d78f36c..b363146 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -391,9 +391,9 @@
 
     auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
 
-    auto calculateExtraBufferCount(Fps maxSupportedRefreshRate,
-                                   std::chrono::nanoseconds presentLatency) const {
-        return SurfaceFlinger::calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+    auto calculateMaxAcquiredBufferCount(Fps refreshRate,
+                                         std::chrono::nanoseconds presentLatency) const {
+        return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
     }
 
     /* ------------------------------------------------------------------------