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
// 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
// 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
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
mConsumerListener(),
mConsumerUsageBits(0),
mConnectedApi(NO_CONNECTED_API),
+ mLinkedToDeath(),
mConnectedProducerListener(),
mSlots(),
mQueue(),
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);
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(
}
mCore->mSharedBufferSlot =
BufferQueueCore::INVALID_BUFFER_SLOT;
+ mCore->mLinkedToDeath = NULL;
mCore->mConnectedProducerListener = NULL;
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
mCore->mConnectedPid = -1;
enum {
ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
+ NEEDS_RELEASE_NOTIFY,
};
class BpProducerListener : public BpInterface<IProducerListener>
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
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