summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorDan Stoza <stoza@google.com>2014-03-21 13:05:51 -0700
committerDan Stoza <stoza@google.com>2014-03-31 14:10:07 -0700
commitf0eaf25e9247edf4d124bedaeb863f7abdf35a3e (patch)
tree15baebb3fa387a1bba3625b3067aa28221cbc8ae /libs
parent96668903e4d11893ea1f68525713542b0adb5404 (diff)
downloadframeworks_native-f0eaf25e9247edf4d124bedaeb863f7abdf35a3e.zip
frameworks_native-f0eaf25e9247edf4d124bedaeb863f7abdf35a3e.tar.gz
frameworks_native-f0eaf25e9247edf4d124bedaeb863f7abdf35a3e.tar.bz2
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
Diffstat (limited to 'libs')
-rw-r--r--libs/gui/Android.mk1
-rw-r--r--libs/gui/BufferQueue.cpp4
-rw-r--r--libs/gui/BufferQueueCore.cpp3
-rw-r--r--libs/gui/BufferQueueProducer.cpp20
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp17
-rw-r--r--libs/gui/IProducerListener.cpp53
-rw-r--r--libs/gui/Surface.cpp5
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp27
-rw-r--r--libs/gui/tests/IGraphicBufferProducer_test.cpp3
9 files changed, 102 insertions, 31 deletions
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 @@ LOCAL_SRC_FILES:= \
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 @@ void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
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 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
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 @@ int BufferQueueProducer::query(int what, int *outValue) {
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 @@ status_t BufferQueueProducer::connect(const sp<android::IBinder> &token,
// 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 @@ status_t BufferQueueProducer::disconnect(int api) {
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 @@ public:
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 @@ status_t BnGraphicBufferProducer::onTransact(
} 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::dispatchUnlockAndPost(va_list args __attribute__((unused))) {
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 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
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 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) {
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 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) {
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 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) {
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