Support SurfaceView synchronization.

Add API for fetching the next frame number to be produced by
a given buffer producer. Add an API to SurfaceComposer to 
defer execution of the current transaction until a given frame number. 
Together these may be used to synchronize app drawing and surface 
control updates.

Change-Id: I8e0f4993332ac0199c768c88581a453fefbaff1d
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 6e16a60..322f2ec 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -170,6 +170,9 @@
     // See IGraphicBufferProducer::getConsumerName
     virtual String8 getConsumerName() const override;
 
+    // See IGraphicBufferProducer::getNextFrameNumber
+    virtual uint64_t getNextFrameNumber() const override;
+
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index b8cba2f..4586839 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -508,6 +508,9 @@
 
     // Returns the name of the connected consumer.
     virtual String8 getConsumerName() const = 0;
+
+    // Returns the number of the next frame which will be dequeued.
+    virtual uint64_t getNextFrameNumber() const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index ed2331b..3f46460 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -109,6 +109,9 @@
     // See IGraphicBufferProducer::getConsumerName
     String8 getConsumerName() const;
 
+    // See IGraphicBufferProducer::getNextFrameNumber
+    uint64_t getNextFrameNumber() const;
+
 protected:
     virtual ~Surface();
 
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 37d953e..aa48718 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -134,6 +134,8 @@
     status_t    setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
     status_t    setCrop(const sp<IBinder>& id, const Rect& crop);
     status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
+    status_t    deferTransactionUntil(const sp<IBinder>& id,
+            const sp<IBinder>& handle, uint64_t frameNumber);
     status_t    destroySurface(const sp<IBinder>& id);
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 9f62f7c..993a92f 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -69,10 +69,15 @@
     status_t    setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
     status_t    setCrop(const Rect& crop);
 
+    // Defers applying any changes made in this transaction until the Layer
+    // identified by handle reaches the given frameNumber
+    status_t deferTransactionUntil(sp<IBinder> handle, uint64_t frameNumber);
+
     static status_t writeSurfaceToParcel(
             const sp<SurfaceControl>& control, Parcel* parcel);
 
     sp<Surface> getSurface() const;
+    sp<IBinder> getHandle() const;
 
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index b2574d0..1711071 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -52,6 +52,7 @@
         eFlagsChanged               = 0x00000040,
         eLayerStackChanged          = 0x00000080,
         eCropChanged                = 0x00000100,
+        eDeferTransaction           = 0x00000200
     };
 
     layer_state_t()
@@ -87,6 +88,8 @@
             uint8_t         reserved;
             matrix22_t      matrix;
             Rect            crop;
+            sp<IBinder>     handle;
+            uint64_t        frameNumber;
             // non POD must be last. see write/read
             Region          transparentRegion;
 };
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 0cb018c..9ef8ff7 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1151,6 +1151,14 @@
     return mConsumerName;
 }
 
+uint64_t BufferQueueProducer::getNextFrameNumber() const {
+    ATRACE_CALL();
+
+    Mutex::Autolock lock(mCore->mMutex);
+    uint64_t nextFrameNumber = mCore->mFrameCounter + 1;
+    return nextFrameNumber;
+}
+
 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/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 8ab963d..640a9f2 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -49,7 +49,8 @@
     SET_GENERATION_NUMBER,
     GET_CONSUMER_NAME,
     SET_MAX_DEQUEUED_BUFFER_COUNT,
-    SET_ASYNC_MODE
+    SET_ASYNC_MODE,
+    GET_NEXT_FRAME_NUMBER
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -326,6 +327,18 @@
         }
         return reply.readString8();
     }
+
+    virtual uint64_t getNextFrameNumber() const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        status_t result = remote()->transact(GET_NEXT_FRAME_NUMBER, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getNextFrameNumber failed to transact: %d", result);
+            return 0;
+        }
+        uint64_t frameNumber = reply.readUint64();
+        return frameNumber;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -508,6 +521,12 @@
             reply->writeString8(getConsumerName());
             return NO_ERROR;
         }
+        case GET_NEXT_FRAME_NUMBER: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            uint64_t frameNumber = getNextFrameNumber();
+            reply->writeUint64(frameNumber);
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index eafda86..06f13e8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -38,6 +38,8 @@
     *reinterpret_cast<layer_state_t::matrix22_t *>(
             output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
     output.write(crop);
+    output.writeStrongBinder(handle);
+    output.writeUint64(frameNumber);
     output.write(transparentRegion);
     return NO_ERROR;
 }
@@ -62,6 +64,8 @@
         return BAD_VALUE;
     }
     input.read(crop);
+    handle = input.readStrongBinder();
+    frameNumber = input.readUint64();
     input.read(transparentRegion);
     return NO_ERROR;
 }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a31876b..9191b2a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -111,6 +111,10 @@
     return result;
 }
 
+uint64_t Surface::getNextFrameNumber() const {
+    return mGraphicBufferProducer->getNextFrameNumber();
+}
+
 String8 Surface::getConsumerName() const {
     return mGraphicBufferProducer->getConsumerName();
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9167a0c..3242f55 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -158,6 +158,9 @@
             const Rect& crop);
     status_t setLayerStack(const sp<SurfaceComposerClient>& client,
             const sp<IBinder>& id, uint32_t layerStack);
+    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
+            const sp<IBinder>& id, const sp<IBinder>& handle,
+            uint64_t frameNumber);
 
     void setDisplaySurface(const sp<IBinder>& token,
             const sp<IGraphicBufferProducer>& bufferProducer);
@@ -383,6 +386,20 @@
     return NO_ERROR;
 }
 
+status_t Composer::deferTransactionUntil(
+        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+        const sp<IBinder>& handle, uint64_t frameNumber) {
+    Mutex::Autolock lock(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s) {
+        return BAD_INDEX;
+    }
+    s->what |= layer_state_t::eDeferTransaction;
+    s->handle = handle;
+    s->frameNumber = frameNumber;
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
@@ -609,6 +626,11 @@
     return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
 }
 
+status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
+        const sp<IBinder>& handle, uint64_t frameNumber) {
+    return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
+}
+
 // ----------------------------------------------------------------------------
 
 void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 1983027..a945358 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -145,6 +145,13 @@
     return mClient->setCrop(mHandle, crop);
 }
 
+status_t SurfaceControl::deferTransactionUntil(sp<IBinder> handle,
+        uint64_t frameNumber) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
+}
+
 status_t SurfaceControl::clearLayerFrameStats() const {
     status_t err = validate();
     if (err < 0) return err;
@@ -190,5 +197,11 @@
     return mSurfaceData;
 }
 
+sp<IBinder> SurfaceControl::getHandle() const
+{
+    Mutex::Autolock lock(mLock);
+    return mHandle;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 48971bc..392b1cc 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -539,6 +539,10 @@
     return String8("VirtualDisplaySurface");
 }
 
+uint64_t VirtualDisplaySurface::getNextFrameNumber() const {
+    return 0;
+}
+
 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 d53d43c..fb37373 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -119,6 +119,7 @@
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
     virtual String8 getConsumerName() const override;
+    virtual uint64_t getNextFrameNumber() const override;
 
     //
     // Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 33af4a5..a7b167f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -66,6 +66,8 @@
         mName("unnamed"),
         mFormat(PIXEL_FORMAT_NONE),
         mTransactionFlags(0),
+        mPendingStateMutex(),
+        mPendingStates(),
         mQueuedFrames(0),
         mSidebandStreamChanged(false),
         mCurrentTransform(0),
@@ -164,6 +166,20 @@
     }
 }
 
+void Layer::markSyncPointsAvailable(const BufferItem& item) {
+    auto pointIter = mLocalSyncPoints.begin();
+    while (pointIter != mLocalSyncPoints.end()) {
+        if ((*pointIter)->getFrameNumber() == item.mFrameNumber) {
+            auto syncPoint = *pointIter;
+            pointIter = mLocalSyncPoints.erase(pointIter);
+            Mutex::Autolock lock(mAvailableFrameMutex);
+            mAvailableFrames.push_back(std::move(syncPoint));
+        } else {
+            ++pointIter;
+        }
+    }
+}
+
 void Layer::onFrameAvailable(const BufferItem& item) {
     // Add this buffer from our internal queue tracker
     { // Autolock scope
@@ -192,30 +208,36 @@
         mQueueItemCondition.broadcast();
     }
 
+    markSyncPointsAvailable(item);
+
     mFlinger->signalLayerUpdate();
 }
 
 void Layer::onFrameReplaced(const BufferItem& item) {
-    Mutex::Autolock lock(mQueueItemLock);
+    { // Autolock scope
+        Mutex::Autolock lock(mQueueItemLock);
 
-    // Ensure that callbacks are handled in order
-    while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-        status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                ms2ns(500));
-        if (result != NO_ERROR) {
-            ALOGE("[%s] Timed out waiting on callback", mName.string());
+        // Ensure that callbacks are handled in order
+        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+                    ms2ns(500));
+            if (result != NO_ERROR) {
+                ALOGE("[%s] Timed out waiting on callback", mName.string());
+            }
         }
+
+        if (mQueueItems.empty()) {
+            ALOGE("Can't replace a frame on an empty queue");
+            return;
+        }
+        mQueueItems.editItemAt(0) = item;
+
+        // Wake up any pending callbacks
+        mLastFrameNumberReceived = item.mFrameNumber;
+        mQueueItemCondition.broadcast();
     }
 
-    if (mQueueItems.empty()) {
-        ALOGE("Can't replace a frame on an empty queue");
-        return;
-    }
-    mQueueItems.editItemAt(0) = item;
-
-    // Wake up any pending callbacks
-    mLastFrameNumberReceived = item.mFrameNumber;
-    mQueueItemCondition.broadcast();
+    markSyncPointsAvailable(item);
 }
 
 void Layer::onSidebandStreamChanged() {
@@ -266,6 +288,22 @@
     return NO_ERROR;
 }
 
+/*
+ * The layer handle is just a BBinder object passed to the client
+ * (remote process) -- we don't keep any reference on our side such that
+ * the dtor is called when the remote side let go of its reference.
+ *
+ * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
+ * this layer when the handle is destroyed.
+ */
+class Layer::Handle : public BBinder, public LayerCleaner {
+    public:
+        Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+            : LayerCleaner(flinger, layer), owner(layer) {}
+
+        wp<Layer> owner;
+};
+
 sp<IBinder> Layer::getHandle() {
     Mutex::Autolock _l(mLock);
 
@@ -274,23 +312,6 @@
 
     mHasSurface = true;
 
-    /*
-     * The layer handle is just a BBinder object passed to the client
-     * (remote process) -- we don't keep any reference on our side such that
-     * the dtor is called when the remote side let go of its reference.
-     *
-     * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
-     * this layer when the handle is destroyed.
-     */
-
-    class Handle : public BBinder, public LayerCleaner {
-        wp<const Layer> mOwner;
-    public:
-        Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
-            : LayerCleaner(flinger, layer), mOwner(layer) {
-        }
-    };
-
     return new Handle(mFlinger, this);
 }
 
@@ -781,6 +802,24 @@
     return static_cast<uint32_t>(producerStickyTransform);
 }
 
+void Layer::addSyncPoint(std::shared_ptr<SyncPoint> point) {
+    uint64_t headFrameNumber = 0;
+    {
+        Mutex::Autolock lock(mQueueItemLock);
+        if (!mQueueItems.empty()) {
+            headFrameNumber = mQueueItems[0].mFrameNumber;
+        } else {
+            headFrameNumber = mLastFrameNumberReceived;
+        }
+    }
+
+    if (point->getFrameNumber() <= headFrameNumber) {
+        point->setFrameAvailable();
+    } else {
+        mLocalSyncPoints.push_back(std::move(point));
+    }
+}
+
 void Layer::setFiltering(bool filtering) {
     mFiltering = filtering;
 }
@@ -895,9 +934,103 @@
 // transaction
 // ----------------------------------------------------------------------------
 
+void Layer::pushPendingState() {
+    if (!mCurrentState.modified) {
+        return;
+    }
+
+    Mutex::Autolock lock(mPendingStateMutex);
+
+    // If this transaction is waiting on the receipt of a frame, generate a sync
+    // point and send it to the remote layer.
+    if (mCurrentState.handle != nullptr) {
+        sp<Handle> handle = static_cast<Handle*>(mCurrentState.handle.get());
+        sp<Layer> handleLayer = handle->owner.promote();
+        if (handleLayer == nullptr) {
+            ALOGE("[%s] Unable to promote Layer handle", mName.string());
+            // If we can't promote the layer we are intended to wait on,
+            // then it is expired or otherwise invalid. Allow this transaction
+            // to be applied as per normal (no synchronization).
+            mCurrentState.handle = nullptr;
+        }
+
+        auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber);
+        handleLayer->addSyncPoint(syncPoint);
+        mRemoteSyncPoints.push_back(std::move(syncPoint));
+
+        // Wake us up to check if the frame has been received
+        setTransactionFlags(eTransactionNeeded);
+    }
+    mPendingStates.push_back(mCurrentState);
+}
+
+void Layer::popPendingState() {
+    auto oldFlags = mCurrentState.flags;
+    mCurrentState = mPendingStates[0];
+    mCurrentState.flags = (oldFlags & ~mCurrentState.mask) | 
+            (mCurrentState.flags & mCurrentState.mask);
+
+    mPendingStates.removeAt(0);
+}
+
+bool Layer::applyPendingStates() {
+    Mutex::Autolock lock(mPendingStateMutex);
+
+    bool stateUpdateAvailable = false;
+    while (!mPendingStates.empty()) {
+        if (mPendingStates[0].handle != nullptr) {
+            if (mRemoteSyncPoints.empty()) {
+                // If we don't have a sync point for this, apply it anyway. It
+                // will be visually wrong, but it should keep us from getting
+                // into too much trouble.
+                ALOGE("[%s] No local sync point found", mName.string());
+                popPendingState();
+                stateUpdateAvailable = true;
+                continue;
+            }
+
+            if (mRemoteSyncPoints.front()->frameIsAvailable()) {
+                // Apply the state update
+                popPendingState();
+                stateUpdateAvailable = true;
+
+                // Signal our end of the sync point and then dispose of it
+                mRemoteSyncPoints.front()->setTransactionApplied();
+                mRemoteSyncPoints.pop_front();
+            }
+            break;
+        } else {
+            popPendingState();
+            stateUpdateAvailable = true;
+        }
+    }
+
+    // If we still have pending updates, wake SurfaceFlinger back up and point
+    // it at this layer so we can process them
+    if (!mPendingStates.empty()) {
+        setTransactionFlags(eTransactionNeeded);
+        mFlinger->setTransactionFlags(eTraversalNeeded);
+    }
+
+    mCurrentState.modified = false;
+    return stateUpdateAvailable;
+}
+
+void Layer::notifyAvailableFrames() {
+    Mutex::Autolock lock(mAvailableFrameMutex);
+    for (auto frame : mAvailableFrames) {
+        frame->setFrameAvailable();
+    }
+}
+
 uint32_t Layer::doTransaction(uint32_t flags) {
     ATRACE_CALL();
 
+    pushPendingState();
+    if (!applyPendingStates()) {
+        return 0;
+    }
+
     const Layer::State& s(getDrawingState());
     const Layer::State& c(getCurrentState());
 
@@ -1017,6 +1150,7 @@
         return false;
     mCurrentState.sequence++;
     mCurrentState.transform.set(x, y);
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1025,6 +1159,7 @@
         return false;
     mCurrentState.sequence++;
     mCurrentState.z = z;
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1033,6 +1168,7 @@
         return false;
     mCurrentState.requested.w = w;
     mCurrentState.requested.h = h;
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1041,6 +1177,7 @@
         return false;
     mCurrentState.sequence++;
     mCurrentState.alpha = alpha;
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1048,11 +1185,13 @@
     mCurrentState.sequence++;
     mCurrentState.transform.set(
             matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
 bool Layer::setTransparentRegionHint(const Region& transparent) {
     mCurrentState.requestedTransparentRegion = transparent;
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1062,6 +1201,8 @@
         return false;
     mCurrentState.sequence++;
     mCurrentState.flags = newFlags;
+    mCurrentState.mask = mask;
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1070,6 +1211,7 @@
         return false;
     mCurrentState.sequence++;
     mCurrentState.requested.crop = crop;
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1079,10 +1221,22 @@
         return false;
     mCurrentState.sequence++;
     mCurrentState.layerStack = layerStack;
+    mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
 
+void Layer::deferTransactionUntil(const sp<IBinder>& handle,
+        uint64_t frameNumber) {
+    mCurrentState.handle = handle;
+    mCurrentState.frameNumber = frameNumber;
+    // We don't set eTransactionNeeded, because just receiving a deferral
+    // request without any other state updates shouldn't actually induce a delay
+    mCurrentState.modified = true;
+    pushPendingState();
+    mCurrentState.modified = false;
+}
+
 void Layer::useSurfaceDamage() {
     if (mFlinger->mForceFullDamage) {
         surfaceDamageRegion = Region::INVALID_REGION;
@@ -1307,9 +1461,35 @@
                 getProducerStickyTransform() != 0);
 
         uint64_t maxFrameNumber = 0;
+        uint64_t headFrameNumber = 0;
         {
             Mutex::Autolock lock(mQueueItemLock);
             maxFrameNumber = mLastFrameNumberReceived;
+            if (!mQueueItems.empty()) {
+                headFrameNumber = mQueueItems[0].mFrameNumber;
+            }
+        }
+
+        bool availableFramesEmpty = true;
+        {
+            Mutex::Autolock lock(mAvailableFrameMutex);
+            availableFramesEmpty = mAvailableFrames.empty();
+        }
+        if (!availableFramesEmpty) {
+            Mutex::Autolock lock(mAvailableFrameMutex);
+            bool matchingFramesFound = false;
+            bool allTransactionsApplied = true;
+            for (auto& frame : mAvailableFrames) {
+                if (headFrameNumber != frame->getFrameNumber()) {
+                    break;
+                }
+                matchingFramesFound = true;
+                allTransactionsApplied &= frame->transactionIsApplied();
+            }
+            if (matchingFramesFound && !allTransactionsApplied) {
+                mFlinger->signalLayerUpdate();
+                return outDirtyRegion;
+            }
         }
 
         status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
@@ -1368,6 +1548,15 @@
             mFlinger->signalLayerUpdate();
         }
 
+        if (!availableFramesEmpty) {
+            Mutex::Autolock lock(mAvailableFrameMutex);
+            auto frameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+            while (!mAvailableFrames.empty() &&
+                    frameNumber == mAvailableFrames.front()->getFrameNumber()) {
+                mAvailableFrames.pop_front();
+            }
+        }
+
         if (updateResult != NO_ERROR) {
             // something happened!
             recomputeVisibleRegions = true;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c1e5e9f..4ff9006 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -36,6 +36,8 @@
 
 #include <private/gui/LayerState.h>
 
+#include <list>
+
 #include "FrameTracker.h"
 #include "Client.h"
 #include "MonitoredProducer.h"
@@ -107,9 +109,17 @@
         uint32_t layerStack;
         uint8_t alpha;
         uint8_t flags;
+        uint8_t mask;
         uint8_t reserved[2];
         int32_t sequence; // changes when visible regions can change
         Transform transform;
+        bool modified;
+
+        // If set, defers this state update until the Layer identified by handle
+        // receives a frame with the given frameNumber
+        sp<IBinder> handle;
+        uint64_t frameNumber;
+
         // the transparentRegion hint is a bit special, it's latched only
         // when we receive a buffer -- this is because it's "content"
         // dependent.
@@ -137,6 +147,7 @@
     bool setFlags(uint8_t flags, uint8_t mask);
     bool setCrop(const Rect& crop);
     bool setLayerStack(uint32_t layerStack);
+    void deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
 
     // If we have received a new buffer this frame, we will pass its surface
     // damage down to hardware composer. Otherwise, we must send a region with
@@ -152,6 +163,7 @@
     Rect computeBounds(const Region& activeTransparentRegion) const;
     Rect computeBounds() const;
 
+    class Handle;
     sp<IBinder> getHandle();
     sp<IGraphicBufferProducer> getProducer() const;
     const String8& getName() const;
@@ -343,6 +355,10 @@
     virtual void onFrameReplaced(const BufferItem& item) override;
     virtual void onSidebandStreamChanged() override;
 
+    // Move frames made available by item in to a list which will
+    // be signalled at the beginning of the next transaction
+    virtual void markSyncPointsAvailable(const BufferItem& item);
+
     void commitTransaction();
 
     // needsLinearFiltering - true if this surface's state requires filtering
@@ -362,6 +378,56 @@
     // Temporary - Used only for LEGACY camera mode.
     uint32_t getProducerStickyTransform() const;
 
+    // -----------------------------------------------------------------------
+
+    class SyncPoint
+    {
+    public:
+        SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
+                mFrameIsAvailable(false), mTransactionIsApplied(false) {}
+
+        uint64_t getFrameNumber() const {
+            return mFrameNumber;
+        }
+
+        bool frameIsAvailable() const {
+            return mFrameIsAvailable;
+        }
+
+        void setFrameAvailable() {
+            mFrameIsAvailable = true;
+        }
+
+        bool transactionIsApplied() const {
+            return mTransactionIsApplied;
+        }
+
+        void setTransactionApplied() {
+            mTransactionIsApplied = true;
+        }
+
+    private:
+        const uint64_t mFrameNumber;
+        std::atomic<bool> mFrameIsAvailable;
+        std::atomic<bool> mTransactionIsApplied;
+    };
+
+    std::list<std::shared_ptr<SyncPoint>> mLocalSyncPoints;
+
+    // Guarded by mPendingStateMutex
+    std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints;
+
+    void addSyncPoint(std::shared_ptr<SyncPoint> point);
+
+    void pushPendingState();
+    void popPendingState();
+    bool applyPendingStates();
+
+    Mutex mAvailableFrameMutex;
+    std::list<std::shared_ptr<SyncPoint>> mAvailableFrames;
+public:
+    void notifyAvailableFrames();
+private:
 
     // -----------------------------------------------------------------------
 
@@ -378,6 +444,10 @@
     State mDrawingState;
     volatile int32_t mTransactionFlags;
 
+    // Accessed from main thread and binder threads
+    Mutex mPendingStateMutex;
+    Vector<State> mPendingStates;
+
     // thread-safe
     volatile int32_t mQueuedFrames;
     volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 79ef92f..68b6b86 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -127,6 +127,10 @@
     return mProducer->getConsumerName();
 }
 
+uint64_t MonitoredProducer::getNextFrameNumber() const {
+    return mProducer->getNextFrameNumber();
+}
+
 IBinder* MonitoredProducer::onAsBinder() {
     return IInterface::asBinder(mProducer).get();
 }
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 3df6f0f..4d2ed6e 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -57,6 +57,7 @@
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
     virtual String8 getConsumerName() const override;
+    virtual uint64_t getNextFrameNumber() const override;
     virtual IBinder* onAsBinder();
 
 private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 285b829..093ca12 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1326,6 +1326,11 @@
     const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
     const size_t count = currentLayers.size();
 
+    // Notify all layers of available frames
+    for (size_t i = 0; i < count; ++i) {
+        currentLayers[i]->notifyAvailableFrames();
+    }
+
     /*
      * Traversal of the children
      * (perform the transaction for each of them if needed)
@@ -2280,6 +2285,11 @@
                 flags |= eTransactionNeeded|eTraversalNeeded;
             }
         }
+        if (what & layer_state_t::eDeferTransaction) {
+            layer->deferTransactionUntil(s.handle, s.frameNumber);
+            // We don't trigger a traversal here because if no other state is
+            // changed, we don't want this to cause any more work
+        }
     }
     return flags;
 }