libgui: Add dequeue/attach timeout

Adds the ability to specify the timeout when dequeueBuffer or
attachBuffer block due to the lack of a free buffer/slot. By default,
these will block indefinitely (which is signified by a timeout of -1).

When a timeout (other than -1) is specified, non-blocking mode is
disabled and the given timeout will be used instead.

Bug: 25196773
Change-Id: I17fdbeebccb7c8d878703d758ac1209608258e61
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9271ed8..c48f237 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -43,7 +43,8 @@
     mCallbackMutex(),
     mNextCallbackTicket(0),
     mCurrentCallbackTicket(0),
-    mCallbackCondition() {}
+    mCallbackCondition(),
+    mDequeueTimeout(-1) {}
 
 BufferQueueProducer::~BufferQueueProducer() {}
 
@@ -271,7 +272,15 @@
                     (acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
                 return WOULD_BLOCK;
             }
-            mCore->mDequeueCondition.wait(mCore->mMutex);
+            if (mDequeueTimeout >= 0) {
+                status_t result = mCore->mDequeueCondition.waitRelative(
+                        mCore->mMutex, mDequeueTimeout);
+                if (result == TIMED_OUT) {
+                    return result;
+                }
+            } else {
+                mCore->mDequeueCondition.wait(mCore->mMutex);
+            }
         }
     } // while (tryAgain)
 
@@ -1012,8 +1021,11 @@
     }
 
     mCore->mBufferHasBeenQueued = false;
-    mCore->mDequeueBufferCannotBlock =  mCore->mConsumerControlledByApp &&
-            producerControlledByApp;
+    mCore->mDequeueBufferCannotBlock = false;
+    if (mDequeueTimeout < 0) {
+        mCore->mDequeueBufferCannotBlock =
+                mCore->mConsumerControlledByApp && producerControlledByApp;
+    }
     mCore->mAllowAllocation = true;
 
     return status;
@@ -1247,7 +1259,16 @@
         mCore->mSingleBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
     }
     mCore->mSingleBufferMode = singleBufferMode;
+    return NO_ERROR;
+}
 
+status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) {
+    ATRACE_CALL();
+    BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
+
+    Mutex::Autolock lock(mCore->mMutex);
+    mDequeueTimeout = timeout;
+    mCore->mDequeueBufferCannotBlock = false;
     return NO_ERROR;
 }