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/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;
         }
     }