Cache frame event history producer-side.

* Producer maintains a recent history of frames.
* Producer only does a binder call if requested
    informatiVon doesn't exist in the cache.
* Consumer sends fences to the producer, which
    can be queried for timestamps without a
    binder call.

Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*

Change-Id: I8a64579407cc2935f5c659462cb227b07ba27e43
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 8cf8b67..a523cd8 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -66,9 +66,9 @@
         virtual void onFrameReplaced(const BufferItem& item) override;
         virtual void onBuffersReleased() override;
         virtual void onSidebandStreamChanged() override;
-        virtual bool addAndGetFrameTimestamps(
+        virtual void addAndGetFrameTimestamps(
                 const NewFrameEventsEntry* newTimestamps,
-                uint64_t frameNumber, FrameTimestamps* outTimestamps) override;
+                FrameEventHistoryDelta* outDelta) override;
     private:
         // mConsumerListener is a weak reference to the IConsumerListener.  This is
         // the raison d'etre of ProxyConsumerListener.
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 9cfb383..e6ee6c6 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -177,8 +177,7 @@
             sp<Fence>* outFence, float outTransformMatrix[16]) override;
 
     // See IGraphicBufferProducer::getFrameTimestamps
-    virtual bool getFrameTimestamps(uint64_t frameNumber,
-            FrameTimestamps* outTimestamps) override;
+    virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
 
     // See IGraphicBufferProducer::getUniqueId
     virtual status_t getUniqueId(uint64_t* outId) const override;
@@ -195,9 +194,8 @@
     // BufferQueueCore::INVALID_BUFFER_SLOT otherwise
     int getFreeSlotLocked() const;
 
-    bool addAndGetFrameTimestamps(
-            const NewFrameEventsEntry* newTimestamps,
-            uint64_t frameNumber, FrameTimestamps* outTimestamps);
+    void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+            FrameEventHistoryDelta* outDelta);
 
     // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
     // block if there are no available slots and we are not in non-blocking
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 6d3bd6c..5076597 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -23,47 +23,52 @@
 #include <utils/Timers.h>
 
 #include <array>
+#include <bitset>
+#include <vector>
 
 namespace android {
 
 
 struct FrameEvents;
+class FrameEventHistoryDelta;
 class String8;
 
 
-enum class SupportableFrameTimestamps {
+enum class FrameEvent {
+    POSTED,
     REQUESTED_PRESENT,
+    LATCH,
     ACQUIRE,
-    REFRESH_START,
-    GL_COMPOSITION_DONE_TIME,
-    DISPLAY_PRESENT_TIME,
-    DISPLAY_RETIRE_TIME,
-    RELEASE_TIME,
-};
-
-
-// The timestamps the consumer sends to the producer over binder.
-struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
-    FrameTimestamps() = default;
-    explicit FrameTimestamps(const FrameEvents& fences);
-
-    uint64_t frameNumber{0};
-    nsecs_t postedTime{0};
-    nsecs_t requestedPresentTime{0};
-    nsecs_t acquireTime{0};
-    nsecs_t refreshStartTime{0};
-    nsecs_t glCompositionDoneTime{0};
-    nsecs_t displayPresentTime{0};
-    nsecs_t displayRetireTime{0};
-    nsecs_t releaseTime{0};
+    FIRST_REFRESH_START,
+    LAST_REFRESH_START,
+    GL_COMPOSITION_DONE,
+    DISPLAY_PRESENT,
+    DISPLAY_RETIRE,
+    RELEASE,
+    EVENT_COUNT, // Not an actual event.
 };
 
 
 // A collection of timestamps corresponding to a single frame.
 struct FrameEvents {
+    bool hasPostedInfo() const;
+    bool hasRequestedPresentInfo() const;
+    bool hasLatchInfo() const;
+    bool hasFirstRefreshStartInfo() const;
+    bool hasLastRefreshStartInfo() const;
+    bool hasAcquireInfo() const;
+    bool hasGpuCompositionDoneInfo() const;
+    bool hasDisplayPresentInfo() const;
+    bool hasDisplayRetireInfo() const;
+    bool hasReleaseInfo() const;
+
     void checkFencesForCompletion();
     void dump(String8& outString) const;
 
+    static constexpr size_t EVENT_COUNT =
+            static_cast<size_t>(FrameEvent::EVENT_COUNT);
+    static_assert(EVENT_COUNT <= 32, "Event count sanity check failed.");
+
     bool valid{false};
     uint64_t frameNumber{0};
 
@@ -72,6 +77,7 @@
     // a) we'll just never get them or b) they're not ready yet.
     bool addPostCompositeCalled{false};
     bool addRetireCalled{false};
+    bool addReleaseCalled{false};
 
     nsecs_t postedTime{0};
     nsecs_t requestedPresentTime{0};
@@ -93,6 +99,39 @@
 };
 
 
+// A short history of frames that are synchronized between the consumer and
+// producer via deltas.
+class FrameEventHistory {
+public:
+    virtual ~FrameEventHistory();
+
+    FrameEvents* getFrame(uint64_t frameNumber);
+    FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
+    void checkFencesForCompletion();
+    void dump(String8& outString) const;
+
+    static constexpr size_t MAX_FRAME_HISTORY = 8;
+
+protected:
+    std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+};
+
+
+// The producer's interface to FrameEventHistory
+class ProducerFrameEventHistory : public FrameEventHistory {
+public:
+    ~ProducerFrameEventHistory() override;
+
+    void updateAcquireFence(uint64_t frameNumber, sp<Fence> acquire);
+    void applyDelta(const FrameEventHistoryDelta& delta);
+
+private:
+    size_t mAcquireOffset{0};
+};
+
+
+// Used by the consumer to create a new frame event record that is
+// partially complete.
 struct NewFrameEventsEntry {
     uint64_t frameNumber{0};
     nsecs_t postedTime{0};
@@ -101,14 +140,38 @@
 };
 
 
-class FrameEventHistory {
+// Used by the consumer to keep track of which fields it already sent to
+// the producer.
+class FrameEventDirtyFields {
 public:
-    FrameEvents* getFrame(uint64_t frameNumber);
-    FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
-    void checkFencesForCompletion();
-    void dump(String8& outString) const;
+    inline void reset() { mBitset.reset(); }
+    inline bool anyDirty() const { return mBitset.any(); }
 
-    void addQueue(const NewFrameEventsEntry& newFrameEntry);
+    template <FrameEvent event>
+    inline void setDirty() {
+        constexpr size_t eventIndex = static_cast<size_t>(event);
+        static_assert(eventIndex < FrameEvents::EVENT_COUNT, "Bad index.");
+        mBitset.set(eventIndex);
+    }
+
+    template <FrameEvent event>
+    inline bool isDirty() const {
+        constexpr size_t eventIndex = static_cast<size_t>(event);
+        static_assert(eventIndex < FrameEvents::EVENT_COUNT, "Bad index.");
+        return mBitset[eventIndex];
+    }
+
+private:
+    std::bitset<FrameEvents::EVENT_COUNT> mBitset;
+};
+
+
+// The consumer's interface to FrameEventHistory
+class ConsumerFrameEventHistory : public FrameEventHistory {
+public:
+    ~ConsumerFrameEventHistory() override;
+
+    void addQueue(const NewFrameEventsEntry& newEntry);
     void addLatch(uint64_t frameNumber, nsecs_t latchTime);
     void addPreComposition(uint64_t frameNumber, nsecs_t refreshStartTime);
     void addPostComposition(uint64_t frameNumber,
@@ -116,14 +179,96 @@
     void addRetire(uint64_t frameNumber, sp<Fence> displayRetire);
     void addRelease(uint64_t frameNumber, sp<Fence> release);
 
+    void getAndResetDelta(FrameEventHistoryDelta* delta);
+
 private:
-    static constexpr size_t MAX_FRAME_HISTORY = 8;
-    std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+    std::array<FrameEventDirtyFields, MAX_FRAME_HISTORY> mFramesDirty;
     size_t mQueueOffset{0};
     size_t mCompositionOffset{0};
     size_t mRetireOffset{0};
     size_t mReleaseOffset{0};
 };
 
+
+// A single frame update from the consumer to producer that can be sent
+// through Binder.
+// Although this may be sent multiple times for the same frame as new
+// timestamps are set, Fences only need to be sent once.
+class FrameEventsDelta : public Flattenable<FrameEventsDelta> {
+friend class ProducerFrameEventHistory;
+public:
+    FrameEventsDelta() = default;
+    FrameEventsDelta(size_t index,
+            const FrameEvents& frameTimestamps,
+            const FrameEventDirtyFields& dirtyFields);
+
+    // Flattenable implementation
+    size_t getFlattenedSize() const;
+    size_t getFdCount() const;
+    status_t flatten(void*& buffer, size_t& size, int*& fds,
+            size_t& count) const;
+    status_t unflatten(void const*& buffer, size_t& size, int const*& fds,
+            size_t& count);
+
+private:
+    static size_t minFlattenedSize();
+
+    size_t mIndex{0};
+    uint64_t mFrameNumber{0};
+
+    bool mAddPostCompositeCalled{0};
+    bool mAddRetireCalled{0};
+    bool mAddReleaseCalled{0};
+
+    nsecs_t mPostedTime{0};
+    nsecs_t mRequestedPresentTime{0};
+    nsecs_t mLatchTime{0};
+    nsecs_t mFirstRefreshStartTime{0};
+    nsecs_t mLastRefreshStartTime{0};
+
+    sp<Fence> mAcquireFence{Fence::NO_FENCE};
+    sp<Fence> mGpuCompositionDoneFence{Fence::NO_FENCE};
+    sp<Fence> mDisplayPresentFence{Fence::NO_FENCE};
+    sp<Fence> mDisplayRetireFence{Fence::NO_FENCE};
+    sp<Fence> mReleaseFence{Fence::NO_FENCE};
+
+    // This is a static method with an auto return value so we can call
+    // it without needing const and non-const versions.
+    template <typename ThisType>
+    static inline auto allFences(ThisType fed) ->
+            std::array<decltype(&fed->mAcquireFence), 5> {
+        return {{
+            &fed->mAcquireFence, &fed->mGpuCompositionDoneFence,
+            &fed->mDisplayPresentFence, &fed->mDisplayRetireFence,
+            &fed->mReleaseFence
+        }};
+    }
+};
+
+
+// A collection of updates from consumer to producer that can be sent
+// through Binder.
+class FrameEventHistoryDelta
+        : public Flattenable<FrameEventHistoryDelta> {
+
+friend class ConsumerFrameEventHistory;
+friend class ProducerFrameEventHistory;
+
+public:
+    // Flattenable implementation.
+    size_t getFlattenedSize() const;
+    size_t getFdCount() const;
+    status_t flatten(void*& buffer, size_t& size, int*& fds,
+            size_t& count) const;
+    status_t unflatten(void const*& buffer, size_t& size, int const*& fds,
+            size_t& count);
+
+private:
+    static size_t minFlattenedSize();
+
+    std::vector<FrameEventsDelta> mDeltas;
+};
+
+
 } // namespace android
 #endif
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 8eab3c5..93dd4ac 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -82,13 +82,11 @@
     // different stream.
     virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
 
-    // Notifies the consumer of any new producer-side events and then queries
-    // the consumer timestamps
-    virtual bool addAndGetFrameTimestamps(
+    // Notifies the consumer of any new producer-side timestamps and
+    // returns the combined frame history that hasn't already been retrieved.
+    virtual void addAndGetFrameTimestamps(
             const NewFrameEventsEntry* /*newTimestamps*/,
-            uint64_t /*frameNumber*/, FrameTimestamps* /*outTimestamps*/) {
-        return false;
-    }
+            FrameEventHistoryDelta* /*outDelta*/) {}
 };
 
 
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 493143a..612a902 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -588,13 +588,8 @@
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) = 0;
 
-    // Attempts to retrieve timestamp information for the given frame number.
-    // If information for the given frame number is not found, returns false.
-    // Returns true otherwise.
-    //
-    // If a fence has not yet signaled the timestamp returned will be 0;
-    virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
-            FrameTimestamps* /*outTimestamps*/) { return false; }
+    // Gets the frame events that haven't already been retrieved.
+    virtual void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {}
 
     // Returns a unique id for this BufferQueue
     virtual status_t getUniqueId(uint64_t* outId) const = 0;
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index bc36970..824e5c4 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -45,7 +45,7 @@
 class IDisplayEventConnection;
 class IMemoryHeap;
 class Rect;
-enum class SupportableFrameTimestamps;
+enum class FrameEvent;
 
 /*
  * This class defines the Binder IPC interface for accessing various
@@ -118,7 +118,7 @@
     /* Returns the frame timestamps supported by SurfaceFlinger.
      */
     virtual status_t getSupportedFrameTimestamps(
-            std::vector<SupportableFrameTimestamps>* outSupported) const = 0;
+            std::vector<FrameEvent>* outSupported) const = 0;
 
     /* set display power mode. depending on the mode, it can either trigger
      * screen on, off or low power mode and wait for it to complete.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index aa5657f..c12d452 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -388,6 +388,9 @@
     mutable bool mQueriedSupportedTimestamps;
     mutable bool mFrameTimestampsSupportsPresent;
     mutable bool mFrameTimestampsSupportsRetire;
+
+    // A cached copy of the FrameEventHistory maintained by the consumer.
+    ProducerFrameEventHistory mFrameEventHistory;
 };
 
 namespace view {
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 6d4335e..f76a282 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -61,15 +61,13 @@
     }
 }
 
-bool BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps(
+void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps(
         const NewFrameEventsEntry* newTimestamps,
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+        FrameEventHistoryDelta* outDelta) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener == nullptr) {
-        return false;
+    if (listener != nullptr) {
+        listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
-    return listener->addAndGetFrameTimestamps(
-            newTimestamps, frameNumber, outTimestamps);
 }
 
 void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 6bd1cfd..e27fd7a 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -975,7 +975,7 @@
         requestedPresentTimestamp,
         acquireFence
     };
-    addAndGetFrameTimestamps(&newFrameEventsEntry, 0, nullptr);
+    addAndGetFrameTimestamps(&newFrameEventsEntry, nullptr);
 
     return NO_ERROR;
 }
@@ -1464,16 +1464,15 @@
     return NO_ERROR;
 }
 
-bool BufferQueueProducer::getFrameTimestamps(
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
-    return addAndGetFrameTimestamps(nullptr, frameNumber, outTimestamps);
+void BufferQueueProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
+    addAndGetFrameTimestamps(nullptr, outDelta);
 }
 
-bool BufferQueueProducer::addAndGetFrameTimestamps(
+void BufferQueueProducer::addAndGetFrameTimestamps(
         const NewFrameEventsEntry* newTimestamps,
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
-    if (newTimestamps == nullptr && outTimestamps == nullptr) {
-        return false;
+        FrameEventHistoryDelta* outDelta) {
+    if (newTimestamps == nullptr && outDelta == nullptr) {
+        return;
     }
 
     ATRACE_CALL();
@@ -1484,10 +1483,8 @@
         listener = mCore->mConsumerListener;
     }
     if (listener != NULL) {
-        return listener->addAndGetFrameTimestamps(
-                newTimestamps, frameNumber, outTimestamps);
+        listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
-    return false;
 }
 
 void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index a919911..4b98cff 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -21,6 +21,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <numeric>
 
 namespace android {
 
@@ -29,25 +30,56 @@
 }
 
 // ============================================================================
-// FrameTimestamps
-// ============================================================================
-
-FrameTimestamps::FrameTimestamps(const FrameEvents& events) :
-    frameNumber(events.frameNumber),
-    postedTime(events.postedTime),
-    requestedPresentTime(events.requestedPresentTime),
-    acquireTime(events.acquireTime),
-    refreshStartTime(events.firstRefreshStartTime),
-    glCompositionDoneTime(events.gpuCompositionDoneTime),
-    displayPresentTime(events.displayPresentTime),
-    displayRetireTime(events.displayRetireTime),
-    releaseTime(events.releaseTime) {}
-
-
-// ============================================================================
 // FrameEvents
 // ============================================================================
 
+bool FrameEvents::hasPostedInfo() const {
+    return isValidTimestamp(postedTime);
+}
+
+bool FrameEvents::hasRequestedPresentInfo() const {
+    return isValidTimestamp(requestedPresentTime);
+}
+
+bool FrameEvents::hasLatchInfo() const {
+    return isValidTimestamp(latchTime);
+}
+
+bool FrameEvents::hasFirstRefreshStartInfo() const {
+    return isValidTimestamp(firstRefreshStartTime);
+}
+
+bool FrameEvents::hasLastRefreshStartInfo() const {
+    // The last refresh start time may continue to update until a new frame
+    // is latched. We know we have the final value once the release or retire
+    // info is set. See ConsumerFrameEventHistory::addRetire/Release.
+    return addRetireCalled || addReleaseCalled;
+}
+
+bool FrameEvents::hasAcquireInfo() const {
+    return isValidTimestamp(acquireTime) || acquireFence->isValid();
+}
+
+bool FrameEvents::hasGpuCompositionDoneInfo() const {
+    // We may not get a gpuCompositionDone in addPostComposite if
+    // client/gles compositing isn't needed.
+    return addPostCompositeCalled;
+}
+
+bool FrameEvents::hasDisplayPresentInfo() const {
+    // We may not get a displayPresent in addPostComposite for HWC1.
+    return addPostCompositeCalled;
+}
+
+bool FrameEvents::hasDisplayRetireInfo() const {
+    // We may not get a displayRetire in addRetire for HWC2.
+    return addRetireCalled;
+}
+
+bool FrameEvents::hasReleaseInfo() const {
+    return addReleaseCalled;
+}
+
 static void checkFenceForCompletion(sp<Fence>* fence, nsecs_t* dstTime) {
     if ((*fence)->isValid()) {
         nsecs_t time = (*fence)->getSignalTime();
@@ -156,6 +188,7 @@
 
 }  // namespace
 
+FrameEventHistory::~FrameEventHistory() = default;
 
 FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber) {
     auto frame = std::find_if(
@@ -209,82 +242,407 @@
     }
 }
 
-void FrameEventHistory::addQueue(const NewFrameEventsEntry& newFrameEntry) {
-    // Overwrite all fields of the frame with default values unless set here.
-    FrameEvents newTimestamps;
-    newTimestamps.frameNumber = newFrameEntry.frameNumber;
-    newTimestamps.postedTime = newFrameEntry.postedTime;
-    newTimestamps.requestedPresentTime = newFrameEntry.requestedPresentTime;
-    newTimestamps.acquireFence = newFrameEntry.acquireFence;
-    newTimestamps.valid = true;
-    mFrames[mQueueOffset] = newTimestamps;
 
-    mQueueOffset = mQueueOffset + 1;
-    if (mQueueOffset >= mFrames.size()) {
-        mQueueOffset = 0;
-    }
-}
+// ============================================================================
+// ProducerFrameEventHistory
+// ============================================================================
 
-void FrameEventHistory::addLatch(uint64_t frameNumber, nsecs_t latchTime) {
-    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+ProducerFrameEventHistory::~ProducerFrameEventHistory() = default;
+
+void ProducerFrameEventHistory::updateAcquireFence(
+        uint64_t frameNumber, sp<Fence> acquire) {
+    FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
     if (frame == nullptr) {
-        ALOGE("FrameEventHistory::addLatch: Did not find frame.");
-        return;
-    }
-    frame->latchTime = latchTime;
-    return;
-}
-
-void FrameEventHistory::addPreComposition(
-        uint64_t frameNumber, nsecs_t refreshStartTime) {
-    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
-    if (frame == nullptr) {
-        ALOGE("FrameEventHistory::addPreComposition: Did not find frame.");
-        return;
-    }
-    frame->lastRefreshStartTime = refreshStartTime;
-    if (!isValidTimestamp(frame->firstRefreshStartTime)) {
-        frame->firstRefreshStartTime = refreshStartTime;
-    }
-}
-
-void FrameEventHistory::addPostComposition(uint64_t frameNumber,
-        sp<Fence> gpuCompositionDone, sp<Fence> displayPresent) {
-    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
-    if (frame == nullptr) {
-        ALOGE("FrameEventHistory::addPostComposition: Did not find frame.");
+        ALOGE("ProducerFrameEventHistory::updateAcquireFence: "
+              "Did not find frame.");
         return;
     }
 
-    // Only get GPU and present info for the first composite.
-    if (!frame->addPostCompositeCalled) {
-        frame->addPostCompositeCalled = true;
-        frame->gpuCompositionDoneFence = gpuCompositionDone;
-        if (!frame->displayPresentFence->isValid()) {
-            frame->displayPresentFence = displayPresent;
+    if (acquire->isValid()) {
+        frame->acquireFence = acquire;
+    } else {
+        // If there isn't an acquire fence, assume that buffer was
+        // ready for the consumer when posted.
+        frame->acquireTime = frame->postedTime;
+    }
+}
+
+static void applyFenceDelta(sp<Fence>* dst, const sp<Fence>& src) {
+    if (src->isValid()) {
+        if ((*dst)->isValid()) {
+            ALOGE("applyFenceDelta: Unexpected fence.");
+        }
+        *dst = src;
+    }
+}
+
+void ProducerFrameEventHistory::applyDelta(
+        const FrameEventHistoryDelta& delta) {
+    for (auto& d : delta.mDeltas) {
+        // Avoid out-of-bounds access.
+        if (d.mIndex >= mFrames.size()) {
+            ALOGE("ProducerFrameEventHistory::applyDelta: Bad index.");
+            return;
+        }
+
+        FrameEvents& frame = mFrames[d.mIndex];
+
+        frame.addPostCompositeCalled = d.mAddPostCompositeCalled != 0;
+        frame.addRetireCalled = d.mAddRetireCalled != 0;
+        frame.addReleaseCalled = d.mAddReleaseCalled != 0;
+
+        frame.postedTime = d.mPostedTime;
+        frame.requestedPresentTime = d.mRequestedPresentTime;
+        frame.latchTime = d.mLatchTime;
+        frame.firstRefreshStartTime = d.mFirstRefreshStartTime;
+        frame.lastRefreshStartTime = d.mLastRefreshStartTime;
+
+        if (frame.frameNumber == d.mFrameNumber) {
+            // Existing frame. Merge.
+            // Consumer never sends timestamps of fences, only the fences
+            // themselves, so we never need to update the fence timestamps here.
+            applyFenceDelta(&frame.acquireFence, d.mAcquireFence);
+            applyFenceDelta(
+                    &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence);
+            applyFenceDelta(&frame.displayPresentFence, d.mDisplayPresentFence);
+            applyFenceDelta(&frame.displayRetireFence, d.mDisplayRetireFence);
+            applyFenceDelta(&frame.releaseFence, d.mReleaseFence);
+        } else {
+            // New frame. Overwrite.
+            frame.frameNumber = d.mFrameNumber;
+
+            frame.gpuCompositionDoneFence = d.mGpuCompositionDoneFence;
+            frame.displayPresentFence = d.mDisplayPresentFence;
+            frame.displayRetireFence = d.mDisplayRetireFence;
+            frame.releaseFence = d.mReleaseFence;
+
+            // Set aquire fence and time at this point.
+            frame.acquireTime = 0;
+            frame.acquireFence = d.mAcquireFence;
+
+            // Reset fence-related timestamps
+            frame.gpuCompositionDoneTime = 0;
+            frame.displayPresentTime = 0;
+            frame.displayRetireTime = 0;
+            frame.releaseTime = 0;
+
+            // The consumer only sends valid frames.
+            frame.valid = true;
         }
     }
 }
 
-void FrameEventHistory::addRetire(
+
+// ============================================================================
+// ConsumerFrameEventHistory
+// ============================================================================
+
+ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
+
+void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) {
+    // Overwrite all fields of the frame with default values unless set here.
+    FrameEvents newTimestamps;
+    newTimestamps.frameNumber = newEntry.frameNumber;
+    newTimestamps.postedTime = newEntry.postedTime;
+    newTimestamps.requestedPresentTime = newEntry.requestedPresentTime;
+    newTimestamps.acquireFence = newEntry.acquireFence;
+    newTimestamps.valid = true;
+    mFrames[mQueueOffset] = newTimestamps;
+    mFramesDirty[mQueueOffset].setDirty<FrameEvent::POSTED>();
+    mFramesDirty[mQueueOffset].setDirty<FrameEvent::ACQUIRE>();
+
+    mQueueOffset = (mQueueOffset + 1) % mFrames.size();
+}
+
+void ConsumerFrameEventHistory::addLatch(
+        uint64_t frameNumber, nsecs_t latchTime) {
+    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+    if (frame == nullptr) {
+        ALOGE("ConsumerFrameEventHistory::addLatch: Did not find frame.");
+        return;
+    }
+    frame->latchTime = latchTime;
+    mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LATCH>();
+}
+
+void ConsumerFrameEventHistory::addPreComposition(
+        uint64_t frameNumber, nsecs_t refreshStartTime) {
+    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+    if (frame == nullptr) {
+        ALOGE("ConsumerFrameEventHistory::addPreComposition: "
+              "Did not find frame.");
+        return;
+    }
+    frame->lastRefreshStartTime = refreshStartTime;
+    mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LAST_REFRESH_START>();
+    if (!isValidTimestamp(frame->firstRefreshStartTime)) {
+        frame->firstRefreshStartTime = refreshStartTime;
+        mFramesDirty[mCompositionOffset].setDirty<FrameEvent::FIRST_REFRESH_START>();
+    }
+}
+
+void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber,
+        sp<Fence> gpuCompositionDone, sp<Fence> displayPresent) {
+    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+    if (frame == nullptr) {
+        ALOGE("ConsumerFrameEventHistory::addPostComposition: "
+              "Did not find frame.");
+        return;
+    }
+    // Only get GPU and present info for the first composite.
+    if (!frame->addPostCompositeCalled) {
+        frame->addPostCompositeCalled = true;
+        frame->gpuCompositionDoneFence = gpuCompositionDone;
+        mFramesDirty[mCompositionOffset].setDirty<FrameEvent::GL_COMPOSITION_DONE>();
+        if (!frame->displayPresentFence->isValid()) {
+            frame->displayPresentFence = displayPresent;
+            mFramesDirty[mCompositionOffset].setDirty<FrameEvent::DISPLAY_PRESENT>();
+        }
+    }
+}
+
+void ConsumerFrameEventHistory::addRetire(
         uint64_t frameNumber, sp<Fence> displayRetire) {
     FrameEvents* frame = getFrame(frameNumber, &mRetireOffset);
     if (frame == nullptr) {
-        ALOGE("FrameEventHistory::addRetire: Did not find frame.");
+        ALOGE("ConsumerFrameEventHistory::addRetire: Did not find frame.");
         return;
     }
     frame->addRetireCalled = true;
     frame->displayRetireFence = displayRetire;
+    mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>();
 }
 
-void FrameEventHistory::addRelease(
+void ConsumerFrameEventHistory::addRelease(
         uint64_t frameNumber, sp<Fence> release) {
     FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
     if (frame == nullptr) {
-        ALOGE("FrameEventHistory::addRelease: Did not find frame.");
+        ALOGE("ConsumerFrameEventHistory::addRelease: Did not find frame.");
         return;
     }
+    frame->addReleaseCalled = true;
     frame->releaseFence = release;
+    mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>();
 }
 
+void ConsumerFrameEventHistory::getAndResetDelta(
+        FrameEventHistoryDelta* delta) {
+    delta->mDeltas.reserve(mFramesDirty.size());
+    for (size_t i = 0; i < mFramesDirty.size(); i++) {
+        if (mFramesDirty[i].anyDirty()) {
+            delta->mDeltas.push_back(
+                    FrameEventsDelta(i, mFrames[i], mFramesDirty[i]));
+            mFramesDirty[i].reset();
+        }
+    }
+}
+
+
+// ============================================================================
+// FrameEventsDelta
+// ============================================================================
+
+FrameEventsDelta::FrameEventsDelta(
+        size_t index,
+        const FrameEvents& frameTimestamps,
+        const FrameEventDirtyFields& dirtyFields)
+    : mIndex(index),
+      mFrameNumber(frameTimestamps.frameNumber),
+      mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled),
+      mAddRetireCalled(frameTimestamps.addRetireCalled),
+      mAddReleaseCalled(frameTimestamps.addReleaseCalled),
+      mPostedTime(frameTimestamps.postedTime),
+      mRequestedPresentTime(frameTimestamps.requestedPresentTime),
+      mLatchTime(frameTimestamps.latchTime),
+      mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime),
+      mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) {
+    mAcquireFence = dirtyFields.isDirty<FrameEvent::ACQUIRE>() ?
+            frameTimestamps.acquireFence : Fence::NO_FENCE;
+    mGpuCompositionDoneFence =
+            dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>() ?
+                    frameTimestamps.gpuCompositionDoneFence : Fence::NO_FENCE;
+    mDisplayPresentFence = dirtyFields.isDirty<FrameEvent::DISPLAY_PRESENT>() ?
+            frameTimestamps.displayPresentFence : Fence::NO_FENCE;
+    mDisplayRetireFence = dirtyFields.isDirty<FrameEvent::DISPLAY_RETIRE>() ?
+            frameTimestamps.displayRetireFence : Fence::NO_FENCE;
+    mReleaseFence = dirtyFields.isDirty<FrameEvent::RELEASE>() ?
+            frameTimestamps.releaseFence : Fence::NO_FENCE;
+}
+
+size_t FrameEventsDelta::minFlattenedSize() {
+    constexpr size_t min =
+            sizeof(FrameEventsDelta::mFrameNumber) +
+            sizeof(uint8_t) + // mIndex
+            sizeof(uint8_t) + // mAddPostCompositeCalled
+            sizeof(uint8_t) + // mAddRetireCalled
+            sizeof(uint8_t) + // mAddReleaseCalled
+            sizeof(FrameEventsDelta::mPostedTime) +
+            sizeof(FrameEventsDelta::mRequestedPresentTime) +
+            sizeof(FrameEventsDelta::mLatchTime) +
+            sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
+            sizeof(FrameEventsDelta::mLastRefreshStartTime);
+    return min;
+}
+
+// Flattenable implementation
+size_t FrameEventsDelta::getFlattenedSize() const {
+    auto fences = allFences(this);
+    return minFlattenedSize() +
+            std::accumulate(fences.begin(), fences.end(), size_t(0),
+                    [](size_t a, const sp<Fence>* fence) {
+                            return a + (*fence)->getFlattenedSize();
+                    });
+}
+
+size_t FrameEventsDelta::getFdCount() const {
+    auto fences = allFences(this);
+    return std::accumulate(fences.begin(), fences.end(), size_t(0),
+            [](size_t a, const sp<Fence>* fence) {
+                return a + (*fence)->getFdCount();
+            });
+}
+
+status_t FrameEventsDelta::flatten(void*& buffer, size_t& size, int*& fds,
+            size_t& count) const {
+    if (size < getFlattenedSize() || count < getFdCount()) {
+        return NO_MEMORY;
+    }
+
+    if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY ||
+            mIndex > std::numeric_limits<uint8_t>::max()) {
+        return BAD_VALUE;
+    }
+
+    FlattenableUtils::write(buffer, size, mFrameNumber);
+
+    // These are static_cast to uint8_t for alignment.
+    FlattenableUtils::write(buffer, size, static_cast<uint8_t>(mIndex));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(mAddPostCompositeCalled));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(mAddRetireCalled));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(mAddReleaseCalled));
+
+    FlattenableUtils::write(buffer, size, mPostedTime);
+    FlattenableUtils::write(buffer, size, mRequestedPresentTime);
+    FlattenableUtils::write(buffer, size, mLatchTime);
+    FlattenableUtils::write(buffer, size, mFirstRefreshStartTime);
+    FlattenableUtils::write(buffer, size, mLastRefreshStartTime);
+
+    // Fences
+    for (auto fence : allFences(this)) {
+        status_t status = (*fence)->flatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size,
+            int const*& fds, size_t& count) {
+    if (size < minFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, mFrameNumber);
+
+    // These were written as uint8_t for alignment.
+    uint8_t temp = 0;
+    FlattenableUtils::read(buffer, size, temp);
+    mIndex = temp;
+    if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    FlattenableUtils::read(buffer, size, temp);
+    mAddPostCompositeCalled = static_cast<bool>(temp);
+    FlattenableUtils::read(buffer, size, temp);
+    mAddRetireCalled = static_cast<bool>(temp);
+    FlattenableUtils::read(buffer, size, temp);
+    mAddReleaseCalled = static_cast<bool>(temp);
+
+    FlattenableUtils::read(buffer, size, mPostedTime);
+    FlattenableUtils::read(buffer, size, mRequestedPresentTime);
+    FlattenableUtils::read(buffer, size, mLatchTime);
+    FlattenableUtils::read(buffer, size, mFirstRefreshStartTime);
+    FlattenableUtils::read(buffer, size, mLastRefreshStartTime);
+
+    // Fences
+    for (auto fence : allFences(this)) {
+        *fence = new Fence;
+        status_t status = (*fence)->unflatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+
+// ============================================================================
+// FrameEventHistoryDelta
+// ============================================================================
+
+size_t FrameEventHistoryDelta::minFlattenedSize() {
+    return sizeof(uint32_t);
+}
+
+size_t FrameEventHistoryDelta::getFlattenedSize() const {
+    return minFlattenedSize() +
+            std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
+                    [](size_t a, const FrameEventsDelta& delta) {
+                            return a + delta.getFlattenedSize();
+                    });
+}
+
+size_t FrameEventHistoryDelta::getFdCount() const {
+    return std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
+            [](size_t a, const FrameEventsDelta& delta) {
+                    return a + delta.getFdCount();
+            });
+}
+
+status_t FrameEventHistoryDelta::flatten(
+            void*& buffer, size_t& size, int*& fds, size_t& count) const {
+    if (mDeltas.size() > FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint32_t>(mDeltas.size()));
+    for (auto& d : mDeltas) {
+        status_t status = d.flatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t FrameEventHistoryDelta::unflatten(
+            void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+    if (size < minFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    uint32_t deltaCount = 0;
+    FlattenableUtils::read(buffer, size, deltaCount);
+    if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    mDeltas.resize(deltaCount);
+    for (auto& d : mDeltas) {
+        status_t status = d.unflatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+
 } // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index a4de7eb..bed7d53 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -429,40 +429,24 @@
         return result;
     }
 
-    virtual bool getFrameTimestamps(uint64_t frameNumber,
-                FrameTimestamps* outTimestamps) {
+    virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(
                 IGraphicBufferProducer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to write token: %d", result);
-            return false;
-        }
-        result = data.writeUint64(frameNumber);
-        if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to write: %d", result);
-            return false;
+            ALOGE("IGBP::getFrameTimestamps failed to write token: %d", result);
+            return;
         }
         result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
         if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to transact: %d", result);
-            return false;
+            ALOGE("IGBP::getFrameTimestamps failed to transact: %d", result);
+            return;
         }
-        bool found = false;
-        result = reply.readBool(&found);
+        result = reply.read(*outDelta);
         if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to read: %d", result);
-            return false;
+            ALOGE("IGBP::getFrameTimestamps failed to read timestamps: %d",
+                    result);
         }
-        if (found) {
-            result = reply.read(*outTimestamps);
-            if (result != NO_ERROR) {
-                ALOGE("getFrameTimestamps failed to read timestamps: %d",
-                        result);
-                return false;
-            }
-        }
-        return found;
     }
 
     virtual status_t getUniqueId(uint64_t* outId) const {
@@ -722,26 +706,14 @@
         }
         case GET_FRAME_TIMESTAMPS: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
-            uint64_t frameNumber = 0;
-            status_t result = data.readUint64(&frameNumber);
+            FrameEventHistoryDelta frameTimestamps;
+            getFrameTimestamps(&frameTimestamps);
+            status_t result = reply->write(frameTimestamps);
             if (result != NO_ERROR) {
-                ALOGE("onTransact failed to read: %d", result);
+                ALOGE("BnGBP::GET_FRAME_TIMESTAMPS failed to write buffer: %d",
+                        result);
                 return result;
             }
-            FrameTimestamps timestamps;
-            bool found = getFrameTimestamps(frameNumber, &timestamps);
-            result = reply->writeBool(found);
-            if (result != NO_ERROR) {
-                ALOGE("onTransact failed to write: %d", result);
-                return result;
-            }
-            if (found) {
-                result = reply->write(timestamps);
-                if (result != NO_ERROR) {
-                    ALOGE("onTransact failed to write timestamps: %d", result);
-                    return result;
-                }
-            }
             return NO_ERROR;
         }
         case GET_UNIQUE_ID: {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index b5fe266..fa2f59a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -159,7 +159,7 @@
     }
 
     virtual status_t getSupportedFrameTimestamps(
-            std::vector<SupportableFrameTimestamps>* outSupported) const {
+            std::vector<FrameEvent>* outSupported) const {
         if (!outSupported) {
             return UNEXPECTED_NULL;
         }
@@ -197,7 +197,7 @@
 
         outSupported->reserve(supported.size());
         for (int32_t s : supported) {
-            outSupported->push_back(static_cast<SupportableFrameTimestamps>(s));
+            outSupported->push_back(static_cast<FrameEvent>(s));
         }
         return NO_ERROR;
     }
@@ -566,7 +566,7 @@
         }
         case GET_SUPPORTED_FRAME_TIMESTAMPS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<SupportableFrameTimestamps> supportedTimestamps;
+            std::vector<FrameEvent> supportedTimestamps;
             status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
             status_t err = reply->writeInt32(result);
             if (err != NO_ERROR) {
@@ -578,7 +578,7 @@
 
             std::vector<int32_t> supported;
             supported.reserve(supportedTimestamps.size());
-            for (SupportableFrameTimestamps s : supportedTimestamps) {
+            for (FrameEvent s : supportedTimestamps) {
                 supported.push_back(static_cast<int32_t>(s));
             }
             return reply->writeInt32Vector(supported);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 5203cce..c29101e 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -145,47 +145,61 @@
         nsecs_t* outReleaseTime) {
     ATRACE_CALL();
 
-    {
-        Mutex::Autolock lock(mMutex);
+    Mutex::Autolock lock(mMutex);
 
-        // Verify the requested timestamps are supported.
-        querySupportedTimestampsLocked();
-        if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
-            return BAD_VALUE;
-        }
-        if (outDisplayRetireTime != nullptr && !mFrameTimestampsSupportsRetire) {
-            return BAD_VALUE;
-        }
+    // Verify the requested timestamps are supported.
+    querySupportedTimestampsLocked();
+    if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
+        return BAD_VALUE;
+    }
+    if (outDisplayRetireTime != nullptr && !mFrameTimestampsSupportsRetire) {
+        return BAD_VALUE;
     }
 
-    FrameTimestamps timestamps;
-    bool found = mGraphicBufferProducer->getFrameTimestamps(frameNumber,
-            &timestamps);
+    FrameEvents* events = mFrameEventHistory.getFrame(frameNumber);
 
-    if (!found) {
+    // Update our cache of events if the requested events are not available.
+    if (events == nullptr ||
+        (outRequestedPresentTime && !events->hasRequestedPresentInfo()) ||
+        (outAcquireTime && !events->hasAcquireInfo()) ||
+        (outRefreshStartTime && !events->hasFirstRefreshStartInfo()) ||
+        (outGlCompositionDoneTime && !events->hasGpuCompositionDoneInfo()) ||
+        (outDisplayPresentTime && !events->hasDisplayPresentInfo()) ||
+        (outDisplayRetireTime && !events->hasDisplayRetireInfo()) ||
+        (outReleaseTime && !events->hasReleaseInfo())) {
+            FrameEventHistoryDelta delta;
+            mGraphicBufferProducer->getFrameTimestamps(&delta);
+            mFrameEventHistory.applyDelta(delta);
+            events = mFrameEventHistory.getFrame(frameNumber);
+    }
+
+    // A record for the requested frame does not exist.
+    if (events == nullptr) {
         return NAME_NOT_FOUND;
     }
 
+    events->checkFencesForCompletion();
+
     if (outRequestedPresentTime) {
-        *outRequestedPresentTime = timestamps.requestedPresentTime;
+        *outRequestedPresentTime = events->requestedPresentTime;
     }
     if (outAcquireTime) {
-        *outAcquireTime = timestamps.acquireTime;
+        *outAcquireTime = events->acquireTime;
     }
     if (outRefreshStartTime) {
-        *outRefreshStartTime = timestamps.refreshStartTime;
+        *outRefreshStartTime = events->firstRefreshStartTime;
     }
     if (outGlCompositionDoneTime) {
-        *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
+        *outGlCompositionDoneTime = events->gpuCompositionDoneTime;
     }
     if (outDisplayPresentTime) {
-        *outDisplayPresentTime = timestamps.displayPresentTime;
+        *outDisplayPresentTime = events->displayPresentTime;
     }
     if (outDisplayRetireTime) {
-        *outDisplayRetireTime = timestamps.displayRetireTime;
+        *outDisplayRetireTime = events->displayRetireTime;
     }
     if (outReleaseTime) {
-        *outReleaseTime = timestamps.releaseTime;
+        *outReleaseTime = events->releaseTime;
     }
 
     return NO_ERROR;
@@ -564,7 +578,7 @@
     }
     mQueriedSupportedTimestamps = true;
 
-    std::vector<SupportableFrameTimestamps> supportedFrameTimestamps;
+    std::vector<FrameEvent> supportedFrameTimestamps;
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
     status_t err = composer->getSupportedFrameTimestamps(
             &supportedFrameTimestamps);
@@ -574,9 +588,9 @@
     }
 
     for (auto sft : supportedFrameTimestamps) {
-        if (sft == SupportableFrameTimestamps::DISPLAY_PRESENT_TIME) {
+        if (sft == FrameEvent::DISPLAY_PRESENT) {
             mFrameTimestampsSupportsPresent = true;
-        } else if (sft == SupportableFrameTimestamps::DISPLAY_RETIRE_TIME) {
+        } else if (sft == FrameEvent::DISPLAY_RETIRE) {
             mFrameTimestampsSupportsRetire = true;
         }
     }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c16af59..2334e47 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2215,24 +2215,16 @@
     mFrameEventHistory.dump(result);
 }
 
-bool Layer::addAndGetFrameTimestamps(
-        const NewFrameEventsEntry* newTimestamps,
-        uint64_t frameNumber, FrameTimestamps *outTimestamps) {
+void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+        FrameEventHistoryDelta *outDelta) {
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     if (newTimestamps) {
         mFrameEventHistory.addQueue(*newTimestamps);
     }
 
-    if (outTimestamps) {
-        FrameEvents* frameEvents = mFrameEventHistory.getFrame(frameNumber);
-        if (frameEvents) {
-            frameEvents->checkFencesForCompletion();
-            *outTimestamps = FrameTimestamps(*frameEvents);
-            return true;
-        }
+    if (outDelta) {
+        mFrameEventHistory.getAndResetDelta(outDelta);
     }
-
-    return false;
 }
 
 std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory(
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 98ea053..b4d8685 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -407,12 +407,10 @@
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
 
-
     std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
 
-    bool addAndGetFrameTimestamps(
-            const NewFrameEventsEntry* newTimestamps,
-            uint64_t frameNumber, FrameTimestamps* outTimestamps);
+    void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
+            FrameEventHistoryDelta* outDelta);
 
     bool getTransformToDisplayInverse() const;
 
@@ -587,7 +585,7 @@
     // Timestamp history for the consumer to query.
     // Accessed by both consumer and producer on main and binder threads.
     Mutex mFrameEventHistoryMutex;
-    FrameEventHistory mFrameEventHistory;
+    ConsumerFrameEventHistory mFrameEventHistory;
 
     // main thread
     sp<GraphicBuffer> mActiveBuffer;
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 4604e01..a2cc531 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -145,9 +145,8 @@
             outTransformMatrix);
 }
 
-bool MonitoredProducer::getFrameTimestamps(
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
-    return mProducer->getFrameTimestamps(frameNumber, outTimestamps);
+void MonitoredProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
+    mProducer->getFrameTimestamps(outDelta);
 }
 
 status_t MonitoredProducer::getUniqueId(uint64_t* outId) const {
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 5a2351f..3e64cae 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -63,8 +63,7 @@
     virtual IBinder* onAsBinder();
     virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
     virtual status_t setAutoRefresh(bool autoRefresh) override;
-    virtual bool getFrameTimestamps(uint64_t frameNumber,
-            FrameTimestamps* outTimestamps) override;
+    virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override;
     virtual status_t getUniqueId(uint64_t* outId) const override;
 
 private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8400136..45d1477 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -567,16 +567,15 @@
 }
 
 status_t SurfaceFlinger::getSupportedFrameTimestamps(
-        std::vector<SupportableFrameTimestamps>* outSupported) const {
+        std::vector<FrameEvent>* outSupported) const {
     *outSupported = {
-        SupportableFrameTimestamps::REQUESTED_PRESENT,
-        SupportableFrameTimestamps::ACQUIRE,
-        SupportableFrameTimestamps::REFRESH_START,
-        SupportableFrameTimestamps::GL_COMPOSITION_DONE_TIME,
+        FrameEvent::REQUESTED_PRESENT,
+        FrameEvent::ACQUIRE,
+        FrameEvent::FIRST_REFRESH_START,
+        FrameEvent::GL_COMPOSITION_DONE,
         getHwComposer().retireFenceRepresentsStartOfScanout() ?
-                SupportableFrameTimestamps::DISPLAY_PRESENT_TIME :
-                SupportableFrameTimestamps::DISPLAY_RETIRE_TIME,
-        SupportableFrameTimestamps::RELEASE_TIME,
+                FrameEvent::DISPLAY_PRESENT : FrameEvent::DISPLAY_RETIRE,
+        FrameEvent::RELEASE,
     };
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5b216dd..5bf989b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -200,7 +200,7 @@
     virtual bool authenticateSurfaceTexture(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
     virtual status_t getSupportedFrameTimestamps(
-            std::vector<SupportableFrameTimestamps>* outSupported) const;
+            std::vector<FrameEvent>* outSupported) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection();
     virtual status_t captureScreen(const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 1ef7065..029937a 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -248,15 +248,13 @@
     }
 }
 
-bool SurfaceFlingerConsumer::addAndGetFrameTimestamps(
+void SurfaceFlingerConsumer::addAndGetFrameTimestamps(
         const NewFrameEventsEntry* newTimestamps,
-        uint64_t frameNumber, FrameTimestamps *outTimestamps) {
+        FrameEventHistoryDelta *outDelta) {
     sp<Layer> l = mLayer.promote();
-    if (!l.get()) {
-        return false;
+    if (l.get()) {
+        l->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
-    return l->addAndGetFrameTimestamps(
-            newTimestamps, frameNumber, outTimestamps);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 0f46ddc..d3f0070 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -84,9 +84,9 @@
     void releasePendingBuffer();
 #endif
 
-    virtual bool addAndGetFrameTimestamps(
+    virtual void addAndGetFrameTimestamps(
             const NewFrameEventsEntry* newTimestamps,
-            uint64_t frameNumber, FrameTimestamps* outTimestamps) override;
+            FrameEventHistoryDelta* outDelta) override;
 
 private:
     virtual void onSidebandStreamChanged();
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 3bdb021..66a3c42 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -600,14 +600,14 @@
 }
 
 status_t SurfaceFlinger::getSupportedFrameTimestamps(
-        std::vector<SupportableFrameTimestamps>* outSupported) const {
+        std::vector<FrameEvent>* outSupported) const {
     *outSupported = {
-        SupportableFrameTimestamps::REQUESTED_PRESENT,
-        SupportableFrameTimestamps::ACQUIRE,
-        SupportableFrameTimestamps::REFRESH_START,
-        SupportableFrameTimestamps::GL_COMPOSITION_DONE_TIME,
-        SupportableFrameTimestamps::DISPLAY_RETIRE_TIME,
-        SupportableFrameTimestamps::RELEASE_TIME,
+        FrameEvent::REQUESTED_PRESENT,
+        FrameEvent::ACQUIRE,
+        FrameEvent::FIRST_REFRESH_START,
+        FrameEvent::GL_COMPOSITION_DONE,
+        FrameEvent::DISPLAY_RETIRE,
+        FrameEvent::RELEASE,
     };
     return NO_ERROR;
 }