BufferQueueProducer::queueBuffer may not drop buffers

Enable BufferQueueProducer::setDequeueTimeout retain existing
dropping behavior. Setting negative and zero to setDequeueTimeout will
not change existing dropping behavior.

BufferQueueProducer::setLegacyBufferDrop can disable buffer dropping
behavior of BufferQueueProducer::queueBuffer. If it's disabled, buffers
will not be dropped unless consumer is SurfaceFlinger.

Bug: 130039639
Change-Id: I8432a7ad386836498e632c67953ad49c6be008bb
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 96c55ac..e0e3431 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -73,6 +73,8 @@
     mActiveBuffers(),
     mDequeueCondition(),
     mDequeueBufferCannotBlock(false),
+    mQueueBufferCanDrop(false),
+    mLegacyBufferDrop(true),
     mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
     mDefaultWidth(1),
     mDefaultHeight(1),
@@ -117,6 +119,8 @@
                             mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
     outResult->appendFormat("%s  mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
                             mDequeueBufferCannotBlock, mAsyncMode);
+    outResult->appendFormat("%s  mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.string(),
+                            mQueueBufferCanDrop, mLegacyBufferDrop);
     outResult->appendFormat("%s  default-size=[%dx%d] default-format=%d ", prefix.string(),
                             mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
     outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 72ae375..4ff69c5 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -889,7 +889,8 @@
         item.mFence = acquireFence;
         item.mFenceTime = acquireFenceTime;
         item.mIsDroppable = mCore->mAsyncMode ||
-                mCore->mDequeueBufferCannotBlock ||
+                (!mCore->mLegacyBufferDrop && mConsumerIsSurfaceFlinger) ||
+                (mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
                 (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
         item.mSurfaceDamage = surfaceDamage;
         item.mQueuedBuffer = true;
@@ -1230,9 +1231,11 @@
     mCore->mConnectedPid = BufferQueueThreadState::getCallingPid();
     mCore->mBufferHasBeenQueued = false;
     mCore->mDequeueBufferCannotBlock = false;
-    if (mDequeueTimeout < 0) {
-        mCore->mDequeueBufferCannotBlock =
-                mCore->mConsumerControlledByApp && producerControlledByApp;
+    mCore->mQueueBufferCanDrop = false;
+    mCore->mLegacyBufferDrop = true;
+    if (mCore->mConsumerControlledByApp && producerControlledByApp) {
+        mCore->mDequeueBufferCannotBlock = mDequeueTimeout < 0;
+        mCore->mQueueBufferCanDrop = mDequeueTimeout <= 0;
     }
 
     mCore->mAllowAllocation = true;
@@ -1516,12 +1519,26 @@
     }
 
     mDequeueTimeout = timeout;
-    mCore->mDequeueBufferCannotBlock = false;
+    if (timeout >= 0) {
+        mCore->mDequeueBufferCannotBlock = false;
+        if (timeout != 0) {
+            mCore->mQueueBufferCanDrop = false;
+        }
+    }
 
     VALIDATE_CONSISTENCY();
     return NO_ERROR;
 }
 
+status_t BufferQueueProducer::setLegacyBufferDrop(bool drop) {
+    ATRACE_CALL();
+    BQ_LOGV("setLegacyBufferDrop: drop = %d", drop);
+
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
+    mCore->mLegacyBufferDrop = drop;
+    return NO_ERROR;
+}
+
 status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
         sp<Fence>* outFence, float outTransformMatrix[16]) {
     ATRACE_CALL();
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index bf44121..0e03b7d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -72,6 +72,7 @@
     GET_FRAME_TIMESTAMPS,
     GET_UNIQUE_ID,
     GET_CONSUMER_USAGE,
+    SET_LEGACY_BUFFER_DROP,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -437,6 +438,20 @@
         return reply.readInt32();
     }
 
+    virtual status_t setLegacyBufferDrop(bool drop) {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeInt32(drop);
+        status_t result = remote()->transact(SET_LEGACY_BUFFER_DROP,
+                data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
+    }
+
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) override {
         Parcel data, reply;
@@ -637,6 +652,10 @@
         return mBase->setDequeueTimeout(timeout);
     }
 
+    status_t setLegacyBufferDrop(bool drop) override {
+        return mBase->setLegacyBufferDrop(drop);
+    }
+
     status_t getLastQueuedBuffer(
             sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence,
@@ -663,6 +682,12 @@
 
 // ----------------------------------------------------------------------
 
+status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) {
+    // No-op for IGBP other than BufferQueue.
+    (void) drop;
+    return INVALID_OPERATION;
+}
+
 status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
     status_t res = OK;
     res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1018,6 +1043,13 @@
             }
             return NO_ERROR;
         }
+        case SET_LEGACY_BUFFER_DROP: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            bool drop = data.readInt32();
+            int result = setLegacyBufferDrop(drop);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 0e80283..9c0ee99 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -226,6 +226,16 @@
     // consumer are controlled by the application.
     bool mDequeueBufferCannotBlock;
 
+    // mQueueBufferCanDrop indicates whether queueBuffer is allowed to drop
+    // buffers in non-async mode. This flag is set during connect when both the
+    // producer and consumer are controlled by application.
+    bool mQueueBufferCanDrop;
+
+    // mLegacyBufferDrop indicates whether mQueueBufferCanDrop is in effect.
+    // If this flag is set mQueueBufferCanDrop is working as explained. If not
+    // queueBuffer will not drop buffers unless consumer is SurfaceFlinger.
+    bool mLegacyBufferDrop;
+
     // mDefaultBufferFormat can be set so it will override the buffer format
     // when it isn't specified in dequeueBuffer.
     PixelFormat mDefaultBufferFormat;
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 415e2a6..d2a47a6 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -174,6 +174,9 @@
     // See IGraphicBufferProducer::setDequeueTimeout
     virtual status_t setDequeueTimeout(nsecs_t timeout) override;
 
+    // see IGraphicBufferProducer::setLegacyBufferDrop
+    virtual status_t setLegacyBufferDrop(bool drop);
+
     // See IGraphicBufferProducer::getLastQueuedBuffer
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) override;
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 9f7e22b..3dde8c8 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -592,12 +592,20 @@
     // non-blocking mode and its corresponding spare buffer (which is used to
     // ensure a buffer is always available).
     //
+    // Note well: queueBuffer will stop buffer dropping behavior if timeout is
+    // strictly positive. If timeout is zero or negative, previous buffer
+    // dropping behavior will not be changed.
+    //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * BAD_VALUE - Failure to adjust the number of available slots. This can
     //               happen because of trying to allocate/deallocate the async
     //               buffer.
     virtual status_t setDequeueTimeout(nsecs_t timeout) = 0;
 
+    // Used to enable/disable buffer drop behavior of queueBuffer.
+    // If it's not used, legacy drop behavior will be retained.
+    virtual status_t setLegacyBufferDrop(bool drop);
+
     // Returns the last queued buffer along with a fence which must signal
     // before the contents of the buffer are read. If there are no buffers in
     // the queue, outBuffer will be populated with nullptr and outFence will be