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