Add sideband streams to BufferQueue and related classes

Sideband streams are essentially a device-specific buffer queue that
bypasses the BufferQueue system. They can be used for situations with
hard real-time requirements like high-quality TV and video playback
with A/V sync. A handle to the stream is provided by the source HAL,
and attached to a BufferQueue. The sink HAL can read buffers via the
stream handle rather than acquiring individual buffers from the
BufferQueue.

Change-Id: Ib3f262eddfc520f4bbe3d9b91753ed7dd09d3a9b
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 7eaf842..867486b 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -67,6 +67,7 @@
         virtual ~ProxyConsumerListener();
         virtual void onFrameAvailable();
         virtual void onBuffersReleased();
+        virtual void onSidebandStreamChanged();
     private:
         // mConsumerListener is a weak reference to the IConsumerListener.  This is
         // the raison d'etre of ProxyConsumerListener.
@@ -204,6 +205,18 @@
     // connected to the specified producer API.
     virtual status_t disconnect(int api);
 
+    // Attaches a sideband buffer stream to the BufferQueue.
+    //
+    // A sideband stream is a device-specific mechanism for passing buffers
+    // from the producer to the consumer without using dequeueBuffer/
+    // queueBuffer. If a sideband stream is present, the consumer can choose
+    // whether to acquire buffers from the sideband stream or from the queued
+    // buffers.
+    //
+    // Passing NULL or a different stream handle will detach the previous
+    // handle if any.
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
+
     /*
      * IGraphicBufferConsumer interface
      */
@@ -306,6 +319,9 @@
     // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
     virtual status_t setTransformHint(uint32_t hint);
 
+    // Retrieve the BufferQueue's sideband stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const;
+
     // dump our state in a String
     virtual void dump(String8& result, const char* prefix) const;
 
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 20db98c..2bdcf28 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -133,6 +133,9 @@
     // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
     virtual status_t setTransformHint(uint32_t hint);
 
+    // Retrieve the sideband buffer stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const;
+
     // dump our state in a String
     virtual void dump(String8& result, const char* prefix) const;
 
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index f4341f8..89f2779 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -22,6 +22,7 @@
 
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
+#include <utils/NativeHandle.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/StrongPointer.h>
@@ -230,6 +231,9 @@
     // mTransformHint is used to optimize for screen rotations.
     uint32_t mTransformHint;
 
+    // mSidebandStream is a handle to the sideband buffer stream, if any
+    sp<NativeHandle> mSidebandStream;
+
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 8912097..250d33c 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -147,6 +147,18 @@
     // connected to the specified producer API.
     virtual status_t disconnect(int api);
 
+    // Attaches a sideband buffer stream to the IGraphicBufferProducer.
+    //
+    // A sideband stream is a device-specific mechanism for passing buffers
+    // from the producer to the consumer without using dequeueBuffer/
+    // queueBuffer. If a sideband stream is present, the consumer can choose
+    // whether to acquire buffers from the sideband stream or from the queued
+    // buffers.
+    //
+    // Passing NULL or a different stream handle will detach the previous
+    // handle if any.
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
+
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index fb21185..100bb26 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -101,11 +101,14 @@
 
     // Implementation of the IConsumerListener interface.  These
     // calls are used to notify the ConsumerBase of asynchronous events in the
-    // BufferQueue.  These methods should not need to be overridden by derived
-    // classes, but if they are overridden the ConsumerBase implementation
-    // must be called from the derived class.
+    // BufferQueue.  The onFrameAvailable and onBuffersReleased methods should
+    // not need to be overridden by derived classes, but if they are overridden
+    // the ConsumerBase implementation must be called from the derived class.
+    // The ConsumerBase version of onSidebandStreamChanged does nothing and can
+    // be overriden by derived classes if they want the notification.
     virtual void onFrameAvailable();
     virtual void onBuffersReleased();
+    virtual void onSidebandStreamChanged();
 
     // freeBufferLocked frees up the given buffer slot.  If the slot has been
     // initialized this will release the reference to the GraphicBuffer in that
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index ac2f9bb..260099e 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -57,6 +57,12 @@
     // This is called without any lock held and can be called concurrently
     // by multiple threads.
     virtual void onBuffersReleased() = 0; /* Asynchronous */
+
+    // onSidebandStreamChanged is called to notify the buffer consumer that the
+    // BufferQueue's sideband buffer stream has changed. This is called when a
+    // stream is first attached and when it is either detached or replaced by a
+    // different stream.
+    virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
 };
 
 
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 9a6645c..67b2b04 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -30,9 +30,10 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-class IConsumerListener;
-class GraphicBuffer;
 class Fence;
+class GraphicBuffer;
+class IConsumerListener;
+class NativeHandle;
 
 class IGraphicBufferConsumer : public IInterface {
 
@@ -266,6 +267,9 @@
     // Return of a value other than NO_ERROR means an unknown error has occurred.
     virtual status_t setTransformHint(uint32_t hint) = 0;
 
+    // Retrieve the sideband buffer stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const = 0;
+
     // dump state into a string
     virtual void dump(String8& result, const char* prefix) const = 0;
 
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 7002530..3fe564d 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -32,6 +32,7 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+class NativeHandle;
 class Surface;
 
 /*
@@ -347,6 +348,18 @@
     //             * api was out of range (see above).
     // * DEAD_OBJECT - the token is hosted by an already-dead process
     virtual status_t disconnect(int api) = 0;
+
+    // Attaches a sideband buffer stream to the IGraphicBufferProducer.
+    //
+    // A sideband stream is a device-specific mechanism for passing buffers
+    // from the producer to the consumer without using dequeueBuffer/
+    // queueBuffer. If a sideband stream is present, the consumer can choose
+    // whether to acquire buffers from the sideband stream or from the queued
+    // buffers.
+    //
+    // Passing NULL or a different stream handle will detach the previous
+    // handle if any.
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 6f8a97c..d8e9756 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -78,6 +78,19 @@
         return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
     }
 
+    /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer.
+     *
+     * A sideband stream is a device-specific mechanism for passing buffers
+     * from the producer to the consumer without using dequeueBuffer/
+     * queueBuffer. If a sideband stream is present, the consumer can choose
+     * whether to acquire buffers from the sideband stream or from the queued
+     * buffers.
+     *
+     * Passing NULL or a different stream handle will detach the previous
+     * handle if any.
+     */
+    void setSidebandStream(const sp<NativeHandle>& stream);
+
 protected:
     virtual ~Surface();
 
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index af857fd..8584dc9 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -93,6 +93,10 @@
     return mProducer->disconnect(api);
 }
 
+status_t BufferQueue::setSidebandStream(const sp<NativeHandle>& stream) {
+    return mProducer->setSidebandStream(stream);
+}
+
 status_t BufferQueue::acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) {
     return mConsumer->acquireBuffer(buffer, presentWhen);
 }
@@ -148,8 +152,19 @@
     return mConsumer->setTransformHint(hint);
 }
 
+sp<NativeHandle> BufferQueue::getSidebandStream() const {
+    return mConsumer->getSidebandStream();
+}
+
 void BufferQueue::dump(String8& result, const char* prefix) const {
     mConsumer->dump(result, prefix);
 }
 
+void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
 }; // namespace android
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index dc7aa15..e34f716 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -395,6 +395,10 @@
     return NO_ERROR;
 }
 
+sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
+    return mCore->mSidebandStream;
+}
+
 void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
     mCore->dump(result, prefix);
 }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 0e9de88..0ff7b80 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -674,6 +674,7 @@
                     }
                     mCore->mConnectedProducerToken = NULL;
                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
+                    mCore->mSidebandStream.clear();
                     mCore->mDequeueCondition.broadcast();
                     listener = mCore->mConsumerListener;
                 } else {
@@ -697,6 +698,12 @@
     return status;
 }
 
+status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) {
+    Mutex::Autolock _l(mCore->mMutex);
+    mCore->mSidebandStream = stream;
+    return NO_ERROR;
+}
+
 void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
     // If we're here, it means that a producer we were connected to died.
     // We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index c5900aa..b6adc54 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -130,6 +130,9 @@
     }
 }
 
+void ConsumerBase::onSidebandStreamChanged() {
+}
+
 void ConsumerBase::abandon() {
     CB_LOGV("abandon");
     Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 5304462..4ccf0ac 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,8 @@
 
 enum {
     ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
-    ON_BUFFER_RELEASED
+    ON_BUFFER_RELEASED,
+    ON_SIDEBAND_STREAM_CHANGED,
 };
 
 class BpConsumerListener : public BpInterface<IConsumerListener>
@@ -49,6 +50,12 @@
         data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
         remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual void onSidebandStreamChanged() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+        remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener");
@@ -67,6 +74,10 @@
             CHECK_INTERFACE(IConsumerListener, data, reply);
             onBuffersReleased();
             return NO_ERROR;
+        case ON_SIDEBAND_STREAM_CHANGED:
+            CHECK_INTERFACE(IConsumerListener, data, reply);
+            onSidebandStreamChanged();
+            return NO_ERROR;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 876c895..c97d15b 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
@@ -195,6 +196,7 @@
     SET_DEFAULT_BUFFER_FORMAT,
     SET_CONSUMER_USAGE_BITS,
     SET_TRANSFORM_HINT,
+    GET_SIDEBAND_STREAM,
     DUMP,
 };
 
@@ -354,6 +356,20 @@
         return reply.readInt32();
     }
 
+    virtual sp<NativeHandle> getSidebandStream() const {
+        Parcel data, reply;
+        status_t err;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) {
+            return NULL;
+        }
+        sp<NativeHandle> stream;
+        if (reply.readInt32()) {
+            stream = NativeHandle::create(reply.readNativeHandle());
+        }
+        return stream;
+    }
+
     virtual void dump(String8& result, const char* prefix) const {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0f461e5..efbe878 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -18,9 +18,10 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
 #include <utils/RefBase.h>
-#include <utils/Vector.h>
 #include <utils/Timers.h>
+#include <utils/Vector.h>
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
@@ -39,6 +40,7 @@
     QUERY,
     CONNECT,
     DISCONNECT,
+    SET_SIDEBAND_STREAM,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -169,6 +171,22 @@
         result = reply.readInt32();
         return result;
     }
+
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream) {
+        Parcel data, reply;
+        status_t result;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        if (stream.get()) {
+            data.writeInt32(true);
+            data.writeNativeHandle(stream->handle());
+        } else {
+            data.writeInt32(false);
+        }
+        if ((result = remote()->transact(SET_SIDEBAND_STREAM, data, &reply)) == NO_ERROR) {
+            result = reply.readInt32();
+        }
+        return result;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
@@ -263,6 +281,16 @@
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
+        case SET_SIDEBAND_STREAM: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            sp<NativeHandle> stream;
+            if (data.readInt32()) {
+                stream = NativeHandle::create(data.readNativeHandle());
+            }
+            status_t result = setSidebandStream(stream);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 474f633..0ca93c8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -25,6 +25,7 @@
 
 #include <utils/Errors.h>
 #include <utils/misc.h>
+#include <utils/NativeHandle.h>
 #include <utils/String8.h>
 #include <utils/Thread.h>
 #include <utils/Trace.h>
@@ -942,12 +943,22 @@
         SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
         visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
     }
+    virtual void setSidebandStream(const sp<NativeHandle>& stream) {
+        ALOG_ASSERT(stream->handle() != NULL);
+        getLayer()->compositionType = HWC_SIDEBAND;
+        getLayer()->sidebandStream = stream->handle();
+    }
     virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
         if (buffer == 0 || buffer->handle == 0) {
             getLayer()->compositionType = HWC_FRAMEBUFFER;
             getLayer()->flags |= HWC_SKIP_LAYER;
             getLayer()->handle = 0;
         } else {
+            if (getLayer()->compositionType == HWC_SIDEBAND) {
+                // If this was a sideband layer but the stream was removed, reset
+                // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
+                getLayer()->compositionType = HWC_FRAMEBUFFER;
+            }
             getLayer()->handle = buffer->handle;
         }
     }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 9f96113..9218bf6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,9 +45,10 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-class GraphicBuffer;
 class Fence;
 class FloatRect;
+class GraphicBuffer;
+class NativeHandle;
 class Region;
 class String8;
 class SurfaceFlinger;
@@ -164,6 +165,7 @@
         virtual void setFrame(const Rect& frame) = 0;
         virtual void setCrop(const FloatRect& crop) = 0;
         virtual void setVisibleRegionScreen(const Region& reg) = 0;
+        virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
         virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
         virtual void setAcquireFenceFd(int fenceFd) = 0;
         virtual void setPlaneAlpha(uint8_t alpha) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index a1820ab..0f87066 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -458,6 +458,10 @@
     return mSource[SOURCE_SINK]->disconnect(api);
 }
 
+status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) {
+    return INVALID_OPERATION;
+}
+
 void VirtualDisplaySurface::updateQueueBufferOutput(
         const QueueBufferOutput& qbo) {
     uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 6899904..c2cd779 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -105,6 +105,7 @@
     virtual status_t connect(const sp<IBinder>& token,
             int api, bool producerControlledByApp, QueueBufferOutput* output);
     virtual status_t disconnect(int api);
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
 
     //
     // Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 465d376..019d892 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -27,6 +27,7 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
+#include <utils/NativeHandle.h>
 #include <utils/StopWatch.h>
 #include <utils/Trace.h>
 
@@ -66,6 +67,7 @@
         mFormat(PIXEL_FORMAT_NONE),
         mTransactionFlags(0),
         mQueuedFrames(0),
+        mSidebandStreamChanged(false),
         mCurrentTransform(0),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentOpacity(true),
@@ -118,7 +120,7 @@
     mBufferQueue = new SurfaceTextureLayer(mFlinger);
     mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-    mSurfaceFlingerConsumer->setFrameAvailableListener(this);
+    mSurfaceFlingerConsumer->setContentsChangedListener(this);
     mSurfaceFlingerConsumer->setName(mName);
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
@@ -158,6 +160,13 @@
     mFlinger->signalLayerUpdate();
 }
 
+void Layer::onSidebandStreamChanged() {
+    if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was false
+        mFlinger->signalLayerUpdate();
+    }
+}
+
 // called with SurfaceFlinger::mStateLock from the drawing thread after
 // the layer has been remove from the current state list (and just before
 // it's removed from the drawing state list)
@@ -413,9 +422,13 @@
     Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
     layer.setVisibleRegionScreen(visible);
 
-    // NOTE: buffer can be NULL if the client never drew into this
-    // layer yet, or if we ran out of memory
-    layer.setBuffer(mActiveBuffer);
+    if (mSidebandStream.get()) {
+        layer.setSidebandStream(mSidebandStream);
+    } else {
+        // NOTE: buffer can be NULL if the client never drew into this
+        // layer yet, or if we ran out of memory
+        layer.setBuffer(mActiveBuffer);
+    }
 }
 
 void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
@@ -907,7 +920,7 @@
 
 bool Layer::onPreComposition() {
     mRefreshPending = false;
-    return mQueuedFrames > 0;
+    return mQueuedFrames > 0 || mSidebandStreamChanged;
 }
 
 void Layer::onPostComposition() {
@@ -950,6 +963,11 @@
 {
     ATRACE_CALL();
 
+    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was true
+        mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+    }
+
     Region outDirtyRegion;
     if (mQueuedFrames > 0) {
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9283eaa..43de999 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -66,7 +66,7 @@
  * This also implements onFrameAvailable(), which notifies SurfaceFlinger
  * that new data has arrived.
  */
-class Layer : public SurfaceFlingerConsumer::FrameAvailableListener {
+class Layer : public SurfaceFlingerConsumer::ContentsChangedListener {
     static int32_t sSequence;
 
 public:
@@ -313,8 +313,9 @@
 
 
 private:
-    // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
+    // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
     virtual void onFrameAvailable();
+    virtual void onSidebandStreamChanged();
 
     void commitTransaction();
 
@@ -351,10 +352,12 @@
 
     // thread-safe
     volatile int32_t mQueuedFrames;
+    volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
     FrameTracker mFrameTracker;
 
     // main thread
     sp<GraphicBuffer> mActiveBuffer;
+    sp<NativeHandle> mSidebandStream;
     Rect mCurrentCrop;
     uint32_t mCurrentTransform;
     uint32_t mCurrentScalingMode;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 6dc093e..a412543 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -21,8 +21,9 @@
 
 #include <private/gui/SyncFeatures.h>
 
-#include <utils/Trace.h>
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
+#include <utils/Trace.h>
 
 namespace android {
 
@@ -112,6 +113,10 @@
     return mTransformToDisplayInverse;
 }
 
+sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
+    return mConsumer->getSidebandStream();
+}
+
 // We need to determine the time when a buffer acquired now will be
 // displayed.  This can be calculated:
 //   time when previous buffer's actual-present fence was signaled
@@ -154,6 +159,26 @@
     return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
 }
 
+void SurfaceFlingerConsumer::setContentsChangedListener(
+        const wp<ContentsChangedListener>& listener) {
+    setFrameAvailableListener(listener);
+    Mutex::Autolock lock(mMutex);
+    mContentsChangedListener = listener;
+}
+
+void SurfaceFlingerConsumer::onSidebandStreamChanged() {
+    sp<ContentsChangedListener> listener;
+    {   // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
+        listener = mContentsChangedListener.promote();
+    }
+
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 688ad32..becd5d3 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -27,6 +27,10 @@
  */
 class SurfaceFlingerConsumer : public GLConsumer {
 public:
+    struct ContentsChangedListener: public FrameAvailableListener {
+        virtual void onSidebandStreamChanged() = 0;
+    };
+
     SurfaceFlingerConsumer(const sp<BufferQueue>& bq, uint32_t tex)
         : GLConsumer(bq, tex, GLConsumer::TEXTURE_EXTERNAL, false)
     {}
@@ -54,9 +58,19 @@
     // must be called from SF main thread
     bool getTransformToDisplayInverse() const;
 
+    // Sets the contents changed listener. This should be used instead of
+    // ConsumerBase::setFrameAvailableListener().
+    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
+
+    sp<NativeHandle> getSidebandStream() const;
+
 private:
     nsecs_t computeExpectedPresent();
 
+    virtual void onSidebandStreamChanged();
+
+    wp<ContentsChangedListener> mContentsChangedListener;
+
     // Indicates this buffer must be transformed by the inverse transform of the screen
     // it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
     // This must be set/read from SurfaceFlinger's main thread.