BufferQueue: Add producer buffer-released callback

Add a callback to the producer side, onBufferReleased, which will be
called every time the consumer releases a buffer back to the
BufferQueue. This will enable a buffer stream splitter to work
autonomously without having to block on dequeueBuffer.

The binder object used for the callback replaces the generic IBinder
token that was passed into IGraphicBufferProducer::connect to detect
the death of the producer. If a producer does not wish to listen for
buffer release events, it can pass in an instance of the
DummyProducerListener class defined in IProducerListener.h, if it even
cares about death events (BufferQueue doesn't enforce the token being
non-NULL, though perhaps we should).

Change-Id: I23935760673524abeafea2b58dccc3583b368710
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 0a77317..04a8a8d 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -21,6 +21,7 @@
 	IDisplayEventConnection.cpp \
 	IGraphicBufferAlloc.cpp \
 	IGraphicBufferProducer.cpp \
+	IProducerListener.cpp \
 	ISensorEventConnection.cpp \
 	ISensorServer.cpp \
 	ISurfaceComposer.cpp \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index c306f9d..6d2cb25 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -119,9 +119,9 @@
     mProducer->cancelBuffer(buf, fence);
 }
 
-status_t BufferQueue::connect(const sp<IBinder>& token,
+status_t BufferQueue::connect(const sp<IProducerListener>& listener,
         int api, bool producerControlledByApp, QueueBufferOutput* output) {
-    return mProducer->connect(token, api, producerControlledByApp, output);
+    return mProducer->connect(listener, api, producerControlledByApp, output);
 }
 
 status_t BufferQueue::disconnect(int api) {
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 300b23a..28bbb1b 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -24,6 +24,7 @@
 #include <gui/BufferQueueCore.h>
 #include <gui/IConsumerListener.h>
 #include <gui/IGraphicBufferAlloc.h>
+#include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
@@ -47,7 +48,7 @@
     mConsumerListener(),
     mConsumerUsageBits(0),
     mConnectedApi(NO_CONNECTED_API),
-    mConnectedProducerToken(),
+    mConnectedProducerListener(),
     mSlots(),
     mQueue(),
     mOverrideMaxBufferCount(0),
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9dd90ba..82d931e 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -25,6 +25,7 @@
 #include <gui/BufferQueueProducer.h>
 #include <gui/IConsumerListener.h>
 #include <gui/IGraphicBufferAlloc.h>
+#include <gui/IProducerListener.h>
 
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -654,7 +655,7 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueProducer::connect(const sp<android::IBinder> &token,
+status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
         int api, bool producerControlledByApp, QueueBufferOutput *output) {
     ATRACE_CALL();
     Mutex::Autolock lock(mCore->mMutex);
@@ -711,16 +712,16 @@
 
             // Set up a death notification so that we can disconnect
             // automatically if the remote producer dies
-            if (token != NULL && token->remoteBinder() != NULL) {
-                status = token->linkToDeath(
+            if (listener != NULL &&
+                    listener->asBinder()->remoteBinder() != NULL) {
+                status = listener->asBinder()->linkToDeath(
                         static_cast<IBinder::DeathRecipient*>(this));
-                if (status == NO_ERROR) {
-                    mCore->mConnectedProducerToken = token;
-                } else {
+                if (status != NO_ERROR) {
                     BQ_LOGE("connect(P): linkToDeath failed: %s (%d)",
                             strerror(-status), status);
                 }
             }
+            mCore->mConnectedProducerListener = listener;
             break;
         default:
             BQ_LOGE("connect(P): unknown API %d", api);
@@ -759,14 +760,15 @@
                     mCore->freeAllBuffersLocked();
 
                     // Remove our death notification callback if we have one
-                    sp<IBinder> token = mCore->mConnectedProducerToken;
-                    if (token != NULL) {
+                    if (mCore->mConnectedProducerListener != NULL) {
+                        sp<IBinder> token =
+                                mCore->mConnectedProducerListener->asBinder();
                         // This can fail if we're here because of the death
                         // notification, but we just ignore it
                         token->unlinkToDeath(
                                 static_cast<IBinder::DeathRecipient*>(this));
                     }
-                    mCore->mConnectedProducerToken = NULL;
+                    mCore->mConnectedProducerListener = NULL;
                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
                     mCore->mSidebandStream.clear();
                     mCore->mDequeueCondition.broadcast();
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 1d4ec1c..50490af 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,6 +27,7 @@
 #include <binder/IInterface.h>
 
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
 
 namespace android {
 // ----------------------------------------------------------------------------
@@ -171,11 +172,16 @@
         return result;
     }
 
-    virtual status_t connect(const sp<IBinder>& token,
+    virtual status_t connect(const sp<IProducerListener>& listener,
             int api, bool producerControlledByApp, QueueBufferOutput* output) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        data.writeStrongBinder(token);
+        if (listener != NULL) {
+            data.writeInt32(1);
+            data.writeStrongBinder(listener->asBinder());
+        } else {
+            data.writeInt32(0);
+        }
         data.writeInt32(api);
         data.writeInt32(producerControlledByApp);
         status_t result = remote()->transact(CONNECT, data, &reply);
@@ -308,13 +314,16 @@
         } break;
         case CONNECT: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
-            sp<IBinder> token = data.readStrongBinder();
+            sp<IProducerListener> listener;
+            if (data.readInt32() == 1) {
+                listener = IProducerListener::asInterface(data.readStrongBinder());
+            }
             int api = data.readInt32();
             bool producerControlledByApp = data.readInt32();
             QueueBufferOutput* const output =
                     reinterpret_cast<QueueBufferOutput *>(
                             reply->writeInplace(sizeof(QueueBufferOutput)));
-            status_t res = connect(token, api, producerControlledByApp, output);
+            status_t res = connect(listener, api, producerControlledByApp, output);
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
new file mode 100644
index 0000000..efe4069
--- /dev/null
+++ b/libs/gui/IProducerListener.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Parcel.h>
+
+#include <gui/IProducerListener.h>
+
+namespace android {
+
+enum {
+    ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpProducerListener : public BpInterface<IProducerListener>
+{
+public:
+    BpProducerListener(const sp<IBinder>& impl)
+        : BpInterface<IProducerListener>(impl) {}
+
+    virtual void onBufferReleased() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+        remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener")
+
+status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data,
+        Parcel* reply, uint32_t flags) {
+    switch (code) {
+        case ON_BUFFER_RELEASED:
+            CHECK_INTERFACE(IProducerListener, data, reply);
+            onBufferReleased();
+            return NO_ERROR;
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+} // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 95f4084..d1ef503 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,6 +27,7 @@
 
 #include <ui/Fence.h>
 
+#include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/GLConsumer.h>
@@ -513,10 +514,10 @@
 int Surface::connect(int api) {
     ATRACE_CALL();
     ALOGV("Surface::connect");
-    static sp<BBinder> sLife = new BBinder();
+    static sp<IProducerListener> listener = new DummyProducerListener();
     Mutex::Autolock lock(mMutex);
     IGraphicBufferProducer::QueueBufferOutput output;
-    int err = mGraphicBufferProducer->connect(sLife, api, mProducerControlledByApp, &output);
+    int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
     if (err == NO_ERROR) {
         uint32_t numPendingBuffers = 0;
         output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 7943476..e578eef 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -17,17 +17,19 @@
 #define LOG_TAG "BufferQueue_test"
 //#define LOG_NDEBUG 0
 
-#include <gtest/gtest.h>
-
-#include <utils/String8.h>
-#include <utils/threads.h>
+#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
 
 #include <ui/GraphicBuffer.h>
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
-#include <gui/BufferQueue.h>
+
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <gtest/gtest.h>
 
 namespace android {
 
@@ -141,7 +143,8 @@
     sp<DummyConsumer> dc(new DummyConsumer);
     mConsumer->consumerConnect(dc, false);
     IGraphicBufferProducer::QueueBufferOutput qbo;
-    mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &qbo);
+    mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+            &qbo);
     mProducer->setBufferCount(4);
 
     int slot;
@@ -207,8 +210,8 @@
     sp<DummyConsumer> dc(new DummyConsumer);
     ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK,
-            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+            NATIVE_WINDOW_API_CPU, false, &output));
 
     ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(-1)); // Index too low
     ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(
@@ -260,8 +263,8 @@
     sp<DummyConsumer> dc(new DummyConsumer);
     ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK,
-            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+            NATIVE_WINDOW_API_CPU, false, &output));
 
     int slot;
     sp<Fence> fence;
@@ -318,8 +321,8 @@
     sp<DummyConsumer> dc(new DummyConsumer);
     ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK,
-            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+            NATIVE_WINDOW_API_CPU, false, &output));
 
     int slot;
     sp<Fence> fence;
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index c2653c2..70a89cd 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -25,13 +25,14 @@
 #include <ui/GraphicBuffer.h>
 
 #include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
 
 #include <vector>
 
 #define ASSERT_OK(x) ASSERT_EQ(OK, (x))
 #define EXPECT_OK(x) EXPECT_EQ(OK, (x))
 
-#define TEST_TOKEN ((IBinder*)(NULL))
+#define TEST_TOKEN ((IProducerListener*)(NULL))
 #define TEST_API NATIVE_WINDOW_API_CPU
 #define TEST_API_OTHER NATIVE_WINDOW_API_EGL // valid API that's not TEST_API
 #define TEST_CONTROLLED_BY_APP false