OSDN Git Service

Eliminate unnecessary calls to onBufferReleased
authorMatthew Bouyack <mbouyack@google.com>
Mon, 3 Oct 2016 23:24:26 +0000 (16:24 -0700)
committerMatthew Bouyack <mbouyack@google.com>
Tue, 4 Oct 2016 19:57:38 +0000 (12:57 -0700)
This change adds a callback to ProducerListener to indicate whether the
listener needs the 'onBufferReleased' notification. This allows us to
avoid making that binder call unnecessarily, saving ~170us per frame on
Android Wear.

By default the new callback returns true, so behavior for existing
clients should be unchanged. Only the DummyProducerListener returns
false.

Also note that it would be simpler to just pass NULL for the
ProducerListener if not for that fact that we still need it for death
notification.

Bug: b/31122630

Change-Id: I730834218a055d89e89f876dd77da8127eb78000

include/gui/BufferQueueCore.h
include/gui/IProducerListener.h
libs/gui/BufferQueueCore.cpp
libs/gui/BufferQueueProducer.cpp
libs/gui/IProducerListener.cpp

index cc5c536..1226feb 100644 (file)
@@ -185,8 +185,12 @@ private:
     // PID of the process which last successfully called connect(...)
     pid_t mConnectedPid;
 
-    // mConnectedProducerToken is used to set a binder death notification on
+    // mLinkedToDeath is used to set a binder death notification on
     // the producer.
+    sp<IProducerListener> mLinkedToDeath;
+
+    // mConnectedProducerListener is used to handle the onBufferReleased
+    // notification.
     sp<IProducerListener> mConnectedProducerListener;
 
     // mSlots is an array of buffer slots that must be mirrored on the producer
index 3848a6c..b7826c6 100644 (file)
@@ -41,6 +41,7 @@ public:
     // This is called without any lock held and can be called concurrently by
     // multiple threads.
     virtual void onBufferReleased() = 0; // Asynchronous
+    virtual bool needsReleaseNotify() = 0;
 };
 
 class IProducerListener : public ProducerListener, public IInterface
@@ -54,12 +55,14 @@ class BnProducerListener : public BnInterface<IProducerListener>
 public:
     virtual status_t onTransact(uint32_t code, const Parcel& data,
             Parcel* reply, uint32_t flags = 0);
+    virtual bool needsReleaseNotify();
 };
 
 class DummyProducerListener : public BnProducerListener
 {
 public:
     virtual void onBufferReleased() {}
+    virtual bool needsReleaseNotify() { return false; }
 };
 
 } // namespace android
index 9cb9c62..fd85c43 100644 (file)
@@ -59,6 +59,7 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
     mConsumerListener(),
     mConsumerUsageBits(0),
     mConnectedApi(NO_CONNECTED_API),
+    mLinkedToDeath(),
     mConnectedProducerListener(),
     mSlots(),
     mQueue(),
index 48b1db8..7020214 100644 (file)
@@ -1113,18 +1113,22 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
                     static_cast<uint32_t>(mCore->mQueue.size()),
                     mCore->mFrameCounter + 1);
 
-            // Set up a death notification so that we can disconnect
-            // automatically if the remote producer dies
-            if (listener != NULL &&
-                    IInterface::asBinder(listener)->remoteBinder() != NULL) {
-                status = IInterface::asBinder(listener)->linkToDeath(
-                        static_cast<IBinder::DeathRecipient*>(this));
-                if (status != NO_ERROR) {
-                    BQ_LOGE("connect: linkToDeath failed: %s (%d)",
-                            strerror(-status), status);
+            if (listener != NULL) {
+                // Set up a death notification so that we can disconnect
+                // automatically if the remote producer dies
+                if (IInterface::asBinder(listener)->remoteBinder() != NULL) {
+                    status = IInterface::asBinder(listener)->linkToDeath(
+                            static_cast<IBinder::DeathRecipient*>(this));
+                    if (status != NO_ERROR) {
+                        BQ_LOGE("connect: linkToDeath failed: %s (%d)",
+                                strerror(-status), status);
+                    }
+                    mCore->mLinkedToDeath = listener;
+                }
+                if (listener->needsReleaseNotify()) {
+                    mCore->mConnectedProducerListener = listener;
                 }
             }
-            mCore->mConnectedProducerListener = listener;
             break;
         default:
             BQ_LOGE("connect: unknown API %d", api);
@@ -1186,9 +1190,9 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) {
                     mCore->freeAllBuffersLocked();
 
                     // Remove our death notification callback if we have one
-                    if (mCore->mConnectedProducerListener != NULL) {
+                    if (mCore->mLinkedToDeath != NULL) {
                         sp<IBinder> token =
-                                IInterface::asBinder(mCore->mConnectedProducerListener);
+                                IInterface::asBinder(mCore->mLinkedToDeath);
                         // This can fail if we're here because of the death
                         // notification, but we just ignore it
                         token->unlinkToDeath(
@@ -1196,6 +1200,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) {
                     }
                     mCore->mSharedBufferSlot =
                             BufferQueueCore::INVALID_BUFFER_SLOT;
+                    mCore->mLinkedToDeath = NULL;
                     mCore->mConnectedProducerListener = NULL;
                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
                     mCore->mConnectedPid = -1;
index 81adc95..da54ce1 100644 (file)
@@ -22,6 +22,7 @@ namespace android {
 
 enum {
     ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
+    NEEDS_RELEASE_NOTIFY,
 };
 
 class BpProducerListener : public BpInterface<IProducerListener>
@@ -37,6 +38,23 @@ public:
         data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
         remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual bool needsReleaseNotify() {
+        bool result;
+        Parcel data, reply;
+        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+        status_t err = remote()->transact(NEEDS_RELEASE_NOTIFY, data, &reply);
+        if (err != NO_ERROR) {
+            ALOGE("IProducerListener: binder call \'needsReleaseNotify\' failed");
+            return true;
+        }
+        err = reply.readBool(&result);
+        if (err != NO_ERROR) {
+            ALOGE("IProducerListener: malformed binder reply");
+            return true;
+        }
+        return result;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -52,8 +70,16 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data,
             CHECK_INTERFACE(IProducerListener, data, reply);
             onBufferReleased();
             return NO_ERROR;
+        case NEEDS_RELEASE_NOTIFY:
+            CHECK_INTERFACE(IProducerListener, data, reply);
+            reply->writeBool(needsReleaseNotify());
+            return NO_ERROR;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
 
+bool BnProducerListener::needsReleaseNotify() {
+    return true;
+}
+
 } // namespace android