SurfaceFlinger: Fix PTS on stale buffers

SurfaceFlinger's (Layer's) shadow copy of the BufferQueue queue was
getting out of sync for a few reasons. This change fixes these by
doing the following:

- Adds a check to re-synchronize the shadow copy every time we
  successfully acquire a buffer by first dropping stale buffers before
  removing the current buffer.
- Avoids trying to perform updates for buffers which have been rejected
  (for incorrect dimensions) by SurfaceFlinger.
- Adds IGraphicBufferConsumer::setShadowQueueSize, which allows the
  consumer to notify the BufferQueue that it is maintaining a shadow
  copy of the queue and prevents it from dropping so many buffers
  during acquireBuffer that it ends up returning a buffer for which the
  consumer has not yet received an onFrameAvailable call.

Bug: 20096136
Change-Id: I78d0738428005fc19b3be85cc8f1db498043612f
(cherry picked from commit 2e36f2283f48ab764b496490c73a132acf21df3a)
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index c7d5e00..2deef0e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -89,7 +89,20 @@
         // the timestamps are being auto-generated by Surface. If the app isn't
         // generating timestamps explicitly, it probably doesn't want frames to
         // be discarded based on them.
+        //
+        // If the consumer is shadowing our queue, we also make sure that we
+        // don't drop so many buffers that the consumer hasn't received the
+        // onFrameAvailable callback for the buffer it acquires. That is, we
+        // want the buffer we return to be in the consumer's shadow queue.
+        size_t droppableBuffers = mCore->mConsumerShadowQueueSize > 1 ?
+                mCore->mConsumerShadowQueueSize - 1 : 0;
         while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+            if (mCore->mConsumerHasShadowQueue && droppableBuffers == 0) {
+                BQ_LOGV("acquireBuffer: no droppable buffers in consumer's"
+                        " shadow queue, continuing");
+                break;
+            }
+
             // If entry[1] is timely, drop entry[0] (and repeat). We apply an
             // additional criterion here: we only drop the earlier buffer if our
             // desiredPresent falls within +/- 1 second of the expected present.
@@ -124,6 +137,7 @@
             }
             mCore->mQueue.erase(front);
             front = mCore->mQueue.begin();
+            --droppableBuffers;
         }
 
         // See if the front buffer is due
@@ -537,6 +551,14 @@
     return mCore->mSidebandStream;
 }
 
+void BufferQueueConsumer::setShadowQueueSize(size_t size) {
+    ATRACE_CALL();
+    BQ_LOGV("setShadowQueueSize: %zu", size);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mConsumerHasShadowQueue = true;
+    mCore->mConsumerShadowQueueSize = size;
+}
+
 void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
     mCore->dump(result, prefix);
 }
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 887f2cb..d0f7afa 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -71,7 +71,9 @@
     mIsAllocating(false),
     mIsAllocatingCondition(),
     mAllowAllocation(true),
-    mBufferAge(0)
+    mBufferAge(0),
+    mConsumerHasShadowQueue(false),
+    mConsumerShadowQueueSize(0)
 {
     if (allocator == NULL) {
         sp<ISurfaceComposer> composer(ComposerService::getComposerService());
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 6658ab1..480dfb6 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -52,6 +52,7 @@
     SET_CONSUMER_USAGE_BITS,
     SET_TRANSFORM_HINT,
     GET_SIDEBAND_STREAM,
+    SET_SHADOW_QUEUE_SIZE,
     DUMP,
 };
 
@@ -269,6 +270,17 @@
         return stream;
     }
 
+    virtual void setShadowQueueSize(size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt64(static_cast<int64_t>(size));
+        status_t result = remote()->transact(SET_SHADOW_QUEUE_SIZE, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("setShadowQueueSize failed (%d)", result);
+            return;
+        }
+    }
+
     virtual void dump(String8& result, const char* prefix) const {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
@@ -423,6 +435,12 @@
             }
             return NO_ERROR;
         }
+        case SET_SHADOW_QUEUE_SIZE: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            size_t size = static_cast<size_t>(data.readInt64());
+            setShadowQueueSize(size);
+            return NO_ERROR;
+        }
         case DUMP: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             String8 result = data.readString8();