Track frame events incrementally and per layer.

* Replaces FenceTracker, which was owned by SurfaceFlinger,
    with FrameEventHistory, which is owned by Layer.
* Updates FrameEventHistory as events occur.
* Changes SurfaceFlinger flag "--fences" to
    "--frame-events".

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

Change-Id: I868c2ef93964656d7e41848243433499e7f45fe7
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index f24f135..8cf8b67 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -66,8 +66,9 @@
         virtual void onFrameReplaced(const BufferItem& item) override;
         virtual void onBuffersReleased() override;
         virtual void onSidebandStreamChanged() override;
-        virtual bool getFrameTimestamps(uint64_t frameNumber,
-                FrameTimestamps* outTimestamps) const override;
+        virtual bool addAndGetFrameTimestamps(
+                const NewFrameEventsEntry* newTimestamps,
+                uint64_t frameNumber, FrameTimestamps* outTimestamps) 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 65dea0d..9cfb383 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -178,7 +178,7 @@
 
     // See IGraphicBufferProducer::getFrameTimestamps
     virtual bool getFrameTimestamps(uint64_t frameNumber,
-            FrameTimestamps* outTimestamps) const override;
+            FrameTimestamps* outTimestamps) override;
 
     // See IGraphicBufferProducer::getUniqueId
     virtual status_t getUniqueId(uint64_t* outId) const override;
@@ -195,6 +195,10 @@
     // BufferQueueCore::INVALID_BUFFER_SLOT otherwise
     int getFreeSlotLocked() const;
 
+    bool addAndGetFrameTimestamps(
+            const NewFrameEventsEntry* newTimestamps,
+            uint64_t frameNumber, FrameTimestamps* outTimestamps);
+
     // 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
     // mode (producer and consumer controlled by the application). If it blocks,
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index b8bfcd7..6d3bd6c 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -17,11 +17,20 @@
 #ifndef ANDROID_GUI_FRAMETIMESTAMPS_H
 #define ANDROID_GUI_FRAMETIMESTAMPS_H
 
-#include <utils/Timers.h>
+#include <ui/Fence.h>
 #include <utils/Flattenable.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <array>
 
 namespace android {
 
+
+struct FrameEvents;
+class String8;
+
+
 enum class SupportableFrameTimestamps {
     REQUESTED_PRESENT,
     ACQUIRE,
@@ -32,8 +41,14 @@
     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};
@@ -43,5 +58,72 @@
     nsecs_t releaseTime{0};
 };
 
+
+// A collection of timestamps corresponding to a single frame.
+struct FrameEvents {
+    void checkFencesForCompletion();
+    void dump(String8& outString) const;
+
+    bool valid{false};
+    uint64_t frameNumber{0};
+
+    // Whether or not certain points in the frame's life cycle have been
+    // encountered help us determine if timestamps aren't available because
+    // a) we'll just never get them or b) they're not ready yet.
+    bool addPostCompositeCalled{false};
+    bool addRetireCalled{false};
+
+    nsecs_t postedTime{0};
+    nsecs_t requestedPresentTime{0};
+    nsecs_t latchTime{0};
+    nsecs_t firstRefreshStartTime{0};
+    nsecs_t lastRefreshStartTime{0};
+
+    nsecs_t acquireTime{0};
+    nsecs_t gpuCompositionDoneTime{0};
+    nsecs_t displayPresentTime{0};
+    nsecs_t displayRetireTime{0};
+    nsecs_t releaseTime{0};
+
+    sp<Fence> acquireFence{Fence::NO_FENCE};
+    sp<Fence> gpuCompositionDoneFence{Fence::NO_FENCE};
+    sp<Fence> displayPresentFence{Fence::NO_FENCE};
+    sp<Fence> displayRetireFence{Fence::NO_FENCE};
+    sp<Fence> releaseFence{Fence::NO_FENCE};
+};
+
+
+struct NewFrameEventsEntry {
+    uint64_t frameNumber{0};
+    nsecs_t postedTime{0};
+    nsecs_t requestedPresentTime{0};
+    sp<Fence> acquireFence{Fence::NO_FENCE};
+};
+
+
+class FrameEventHistory {
+public:
+    FrameEvents* getFrame(uint64_t frameNumber);
+    FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
+    void checkFencesForCompletion();
+    void dump(String8& outString) const;
+
+    void addQueue(const NewFrameEventsEntry& newFrameEntry);
+    void addLatch(uint64_t frameNumber, nsecs_t latchTime);
+    void addPreComposition(uint64_t frameNumber, nsecs_t refreshStartTime);
+    void addPostComposition(uint64_t frameNumber,
+            sp<Fence> gpuCompositionDone, sp<Fence> displayPresent);
+    void addRetire(uint64_t frameNumber, sp<Fence> displayRetire);
+    void addRelease(uint64_t frameNumber, sp<Fence> release);
+
+private:
+    static constexpr size_t MAX_FRAME_HISTORY = 8;
+    std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+    size_t mQueueOffset{0};
+    size_t mCompositionOffset{0};
+    size_t mRetireOffset{0};
+    size_t mReleaseOffset{0};
+};
+
 } // namespace android
 #endif
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 0ab7590..8eab3c5 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -82,10 +82,13 @@
     // different stream.
     virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
 
-    // See IGraphicBufferProducer::getFrameTimestamps
-    // This queries the consumer for the timestamps
-    virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
-            FrameTimestamps* /*outTimestamps*/) const { return false; }
+    // Notifies the consumer of any new producer-side events and then queries
+    // the consumer timestamps
+    virtual bool addAndGetFrameTimestamps(
+            const NewFrameEventsEntry* /*newTimestamps*/,
+            uint64_t /*frameNumber*/, FrameTimestamps* /*outTimestamps*/) {
+        return false;
+    }
 };
 
 
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 20cffe0..493143a 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -594,7 +594,7 @@
     //
     // If a fence has not yet signaled the timestamp returned will be 0;
     virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
-            FrameTimestamps* /*outTimestamps*/) const { return false; }
+            FrameTimestamps* /*outTimestamps*/) { return false; }
 
     // Returns a unique id for this BufferQueue
     virtual status_t getUniqueId(uint64_t* outId) const = 0;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 9ba85a6..bf758ce 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -71,6 +71,7 @@
         "ConsumerBase.cpp",
         "CpuConsumer.cpp",
         "DisplayEventReceiver.cpp",
+        "FrameTimestamps.cpp",
         "GLConsumer.cpp",
         "GraphicBufferAlloc.cpp",
         "GuiConfig.cpp",
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 47f5eba..6d4335e 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -61,13 +61,15 @@
     }
 }
 
-bool BufferQueue::ProxyConsumerListener::getFrameTimestamps(
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) const {
+bool BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps(
+        const NewFrameEventsEntry* newTimestamps,
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
-        return listener->getFrameTimestamps(frameNumber, outTimestamps);
+    if (listener == nullptr) {
+        return false;
     }
-    return false;
+    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 81d4f31..6bd1cfd 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -740,19 +740,19 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
 
-    int64_t timestamp;
+    int64_t requestedPresentTimestamp;
     bool isAutoTimestamp;
     android_dataspace dataSpace;
     Rect crop(Rect::EMPTY_RECT);
     int scalingMode;
     uint32_t transform;
     uint32_t stickyTransform;
-    sp<Fence> fence;
-    input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode,
-            &transform, &fence, &stickyTransform);
+    sp<Fence> acquireFence;
+    input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
+            &crop, &scalingMode, &transform, &acquireFence, &stickyTransform);
     Region surfaceDamage = input.getSurfaceDamage();
 
-    if (fence == NULL) {
+    if (acquireFence == NULL) {
         BQ_LOGE("queueBuffer: fence is NULL");
         return BAD_VALUE;
     }
@@ -771,6 +771,7 @@
     sp<IConsumerListener> frameAvailableListener;
     sp<IConsumerListener> frameReplacedListener;
     int callbackTicket = 0;
+    uint64_t currentFrameNumber = 0;
     BufferItem item;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
@@ -809,8 +810,9 @@
 
         BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
                 " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
-                slot, mCore->mFrameCounter + 1, timestamp, dataSpace,
-                crop.left, crop.top, crop.right, crop.bottom, transform,
+                slot, mCore->mFrameCounter + 1, requestedPresentTimestamp,
+                dataSpace, crop.left, crop.top, crop.right, crop.bottom,
+                transform,
                 BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
 
         const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
@@ -828,11 +830,14 @@
             dataSpace = mCore->mDefaultBufferDataSpace;
         }
 
-        mSlots[slot].mFence = fence;
+        mSlots[slot].mFence = acquireFence;
         mSlots[slot].mBufferState.queue();
 
+        // Increment the frame counter and store a local version of it
+        // for use outside the lock on mCore->mMutex.
         ++mCore->mFrameCounter;
-        mSlots[slot].mFrameNumber = mCore->mFrameCounter;
+        currentFrameNumber = mCore->mFrameCounter;
+        mSlots[slot].mFrameNumber = currentFrameNumber;
 
         item.mAcquireCalled = mSlots[slot].mAcquireCalled;
         item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
@@ -842,12 +847,12 @@
         item.mTransformToDisplayInverse =
                 (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
         item.mScalingMode = static_cast<uint32_t>(scalingMode);
-        item.mTimestamp = timestamp;
+        item.mTimestamp = requestedPresentTimestamp;
         item.mIsAutoTimestamp = isAutoTimestamp;
         item.mDataSpace = dataSpace;
-        item.mFrameNumber = mCore->mFrameCounter;
+        item.mFrameNumber = currentFrameNumber;
         item.mSlot = slot;
-        item.mFence = fence;
+        item.mFence = acquireFence;
         item.mIsDroppable = mCore->mAsyncMode ||
                 mCore->mDequeueBufferCannotBlock ||
                 (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
@@ -958,10 +963,20 @@
         // small trade-off in favor of latency rather than throughput.
         mLastQueueBufferFence->waitForever("Throttling EGL Production");
     }
-    mLastQueueBufferFence = fence;
+    mLastQueueBufferFence = acquireFence;
     mLastQueuedCrop = item.mCrop;
     mLastQueuedTransform = item.mTransform;
 
+    // Update and get FrameEventHistory.
+    nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    NewFrameEventsEntry newFrameEventsEntry = {
+        currentFrameNumber,
+        postedTime,
+        requestedPresentTimestamp,
+        acquireFence
+    };
+    addAndGetFrameTimestamps(&newFrameEventsEntry, 0, nullptr);
+
     return NO_ERROR;
 }
 
@@ -1449,18 +1464,28 @@
     return NO_ERROR;
 }
 
-bool BufferQueueProducer::getFrameTimestamps(uint64_t frameNumber,
-        FrameTimestamps* outTimestamps) const {
-    ATRACE_CALL();
-    BQ_LOGV("getFrameTimestamps, %" PRIu64, frameNumber);
-    sp<IConsumerListener> listener;
+bool BufferQueueProducer::getFrameTimestamps(
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+    return addAndGetFrameTimestamps(nullptr, frameNumber, outTimestamps);
+}
 
+bool BufferQueueProducer::addAndGetFrameTimestamps(
+        const NewFrameEventsEntry* newTimestamps,
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+    if (newTimestamps == nullptr && outTimestamps == nullptr) {
+        return false;
+    }
+
+    ATRACE_CALL();
+    BQ_LOGV("addAndGetFrameTimestamps");
+    sp<IConsumerListener> listener;
     {
         Mutex::Autolock lock(mCore->mMutex);
         listener = mCore->mConsumerListener;
     }
     if (listener != NULL) {
-        return listener->getFrameTimestamps(frameNumber, outTimestamps);
+        return listener->addAndGetFrameTimestamps(
+                newTimestamps, frameNumber, outTimestamps);
     }
     return false;
 }
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
new file mode 100644
index 0000000..a919911
--- /dev/null
+++ b/libs/gui/FrameTimestamps.cpp
@@ -0,0 +1,290 @@
+/*
+* Copyright 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <gui/FrameTimestamps.h>
+
+#include <inttypes.h>
+#include <utils/String8.h>
+
+#include <algorithm>
+#include <limits>
+
+namespace android {
+
+static inline bool isValidTimestamp(nsecs_t time) {
+    return time > 0 && time < INT64_MAX;
+}
+
+// ============================================================================
+// 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
+// ============================================================================
+
+static void checkFenceForCompletion(sp<Fence>* fence, nsecs_t* dstTime) {
+    if ((*fence)->isValid()) {
+        nsecs_t time = (*fence)->getSignalTime();
+        if (isValidTimestamp(time)) {
+            *dstTime = time;
+            *fence = Fence::NO_FENCE;
+        }
+    }
+}
+
+void FrameEvents::checkFencesForCompletion() {
+    checkFenceForCompletion(&acquireFence, &acquireTime);
+    checkFenceForCompletion(&gpuCompositionDoneFence, &gpuCompositionDoneTime);
+    checkFenceForCompletion(&displayPresentFence, &displayPresentTime);
+    checkFenceForCompletion(&displayRetireFence, &displayRetireTime);
+    checkFenceForCompletion(&releaseFence, &releaseTime);
+}
+
+void FrameEvents::dump(String8& outString) const
+{
+    if (!valid) {
+        return;
+    }
+
+    outString.appendFormat("-- Frame %" PRIu64 "\n", frameNumber);
+    outString.appendFormat("--- Posted      \t%" PRId64 "\n", postedTime);
+    outString.appendFormat("--- Req. Present\t%" PRId64 "\n", requestedPresentTime);
+
+    outString.appendFormat("--- Latched     \t");
+    if (isValidTimestamp(latchTime)) {
+        outString.appendFormat("%" PRId64 "\n", latchTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    outString.appendFormat("--- Refresh (First)\t");
+    if (isValidTimestamp(firstRefreshStartTime)) {
+        outString.appendFormat("%" PRId64 "\n", firstRefreshStartTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    outString.appendFormat("--- Refresh (Last)\t");
+    if (isValidTimestamp(lastRefreshStartTime)) {
+        outString.appendFormat("%" PRId64 "\n", lastRefreshStartTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    outString.appendFormat("--- Acquire     \t");
+    if (isValidTimestamp(acquireTime)) {
+        outString.appendFormat("%" PRId64 "\n", acquireTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    outString.appendFormat("--- GPU Composite Done\t");
+    if (isValidTimestamp(gpuCompositionDoneTime)) {
+        outString.appendFormat("%" PRId64 "\n", gpuCompositionDoneTime);
+    } else if (!addPostCompositeCalled || gpuCompositionDoneFence->isValid()) {
+        outString.appendFormat("Pending\n");
+    } else {
+        outString.appendFormat("N/A\n");
+    }
+
+    outString.appendFormat("--- Display Present\t");
+    if (isValidTimestamp(displayPresentTime)) {
+        outString.appendFormat("%" PRId64 "\n", displayPresentTime);
+    } else if (!addPostCompositeCalled || displayPresentFence->isValid()) {
+        outString.appendFormat("Pending\n");
+    } else {
+        outString.appendFormat("N/A\n");
+    }
+
+    outString.appendFormat("--- Display Retire\t");
+    if (isValidTimestamp(displayRetireTime)) {
+        outString.appendFormat("%" PRId64 "\n", displayRetireTime);
+    } else if (!addRetireCalled || displayRetireFence->isValid()) {
+        outString.appendFormat("Pending\n");
+    } else {
+        outString.appendFormat("N/A\n");
+    }
+
+    outString.appendFormat("--- Release     \t");
+    if (isValidTimestamp(releaseTime)) {
+        outString.appendFormat("%" PRId64 "\n", releaseTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+}
+
+
+// ============================================================================
+// FrameEventHistory
+// ============================================================================
+
+namespace {
+
+struct FrameNumberEqual {
+    FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {}
+    bool operator()(const FrameEvents& frame) {
+        return frame.valid && mFrameNumber == frame.frameNumber;
+    }
+    const uint64_t mFrameNumber;
+};
+
+}  // namespace
+
+
+FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber) {
+    auto frame = std::find_if(
+            mFrames.begin(), mFrames.end(), FrameNumberEqual(frameNumber));
+    return frame == mFrames.end() ? nullptr : &(*frame);
+}
+
+FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber, size_t* iHint) {
+    *iHint = std::min(*iHint, mFrames.size());
+    auto hint = mFrames.begin() + *iHint;
+    auto frame = std::find_if(
+            hint, mFrames.end(), FrameNumberEqual(frameNumber));
+    if (frame == mFrames.end()) {
+        frame = std::find_if(
+                mFrames.begin(), hint, FrameNumberEqual(frameNumber));
+        if (frame == hint) {
+            return nullptr;
+        }
+    }
+    *iHint = static_cast<size_t>(std::distance(mFrames.begin(), frame));
+    return &(*frame);
+}
+
+void FrameEventHistory::checkFencesForCompletion() {
+    for (auto& frame : mFrames) {
+        frame.checkFencesForCompletion();
+    }
+}
+
+// Uses !|valid| as the MSB.
+static bool FrameNumberLessThan(
+        const FrameEvents& lhs, const FrameEvents& rhs) {
+    if (lhs.valid == rhs.valid) {
+        return lhs.frameNumber < rhs.frameNumber;
+    }
+    return lhs.valid;
+}
+
+void FrameEventHistory::dump(String8& outString) const {
+    auto earliestFrame = std::min_element(
+            mFrames.begin(), mFrames.end(), &FrameNumberLessThan);
+    if (!earliestFrame->valid) {
+        outString.appendFormat("-- N/A\n");
+        return;
+    }
+    for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) {
+        frame->dump(outString);
+    }
+    for (auto frame = mFrames.begin(); frame != earliestFrame; ++frame) {
+        frame->dump(outString);
+    }
+}
+
+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;
+    }
+}
+
+void FrameEventHistory::addLatch(uint64_t frameNumber, nsecs_t latchTime) {
+    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+    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.");
+        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;
+        }
+    }
+}
+
+void FrameEventHistory::addRetire(
+        uint64_t frameNumber, sp<Fence> displayRetire) {
+    FrameEvents* frame = getFrame(frameNumber, &mRetireOffset);
+    if (frame == nullptr) {
+        ALOGE("FrameEventHistory::addRetire: Did not find frame.");
+        return;
+    }
+    frame->addRetireCalled = true;
+    frame->displayRetireFence = displayRetire;
+}
+
+void FrameEventHistory::addRelease(
+        uint64_t frameNumber, sp<Fence> release) {
+    FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
+    if (frame == nullptr) {
+        ALOGE("FrameEventHistory::addRelease: Did not find frame.");
+        return;
+    }
+    frame->releaseFence = release;
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 89f852c..a4de7eb 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -430,7 +430,7 @@
     }
 
     virtual bool getFrameTimestamps(uint64_t frameNumber,
-                FrameTimestamps* outTimestamps) const {
+                FrameTimestamps* outTimestamps) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(
                 IGraphicBufferProducer::getInterfaceDescriptor());
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 7135ed3..dd8719a 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -10,7 +10,6 @@
     DispSync.cpp \
     EventControlThread.cpp \
     EventThread.cpp \
-    FenceTracker.cpp \
     FrameTracker.cpp \
     GpuService.cpp \
     Layer.cpp \
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
deleted file mode 100644
index 4dac0db..0000000
--- a/services/surfaceflinger/FenceTracker.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <inttypes.h>
-#include "FenceTracker.h"
-#include "Layer.h"
-#include <utils/Trace.h>
-
-namespace android {
-
-FenceTracker::FenceTracker() :
-        mFrameCounter(0),
-        mOffset(0),
-        mFrames(),
-        mMutex() {
-}
-
-void FenceTracker::dump(String8* outString) {
-    Mutex::Autolock lock(mMutex);
-    checkFencesForCompletion();
-
-    for (size_t i = 0; i < MAX_FRAME_HISTORY; i++) {
-        int index = (mOffset + i) % MAX_FRAME_HISTORY;
-        const FrameRecord& frame = mFrames[index];
-
-        outString->appendFormat("Frame %" PRIu64 "\n", frame.frameId);
-        outString->appendFormat("- Refresh start\t%" PRId64 "\n",
-                frame.refreshStartTime);
-
-        if (frame.glesCompositionDoneTime) {
-            outString->appendFormat("- GLES done\t%" PRId64 "\n",
-                    frame.glesCompositionDoneTime);
-        } else if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
-            outString->append("- GLES done\tNot signaled\n");
-        }
-
-        if (frame.presentTime) {
-            outString->appendFormat("- Present\t%" PRId64 "\n",
-                    frame.presentTime);
-        } else if (frame.presentFence != Fence::NO_FENCE) {
-            outString->append("- Present\tNot signaled\n");
-        }
-
-        if (frame.retireTime) {
-            outString->appendFormat("- Retire\t%" PRId64 "\n",
-                    frame.retireTime);
-        } else if (frame.retireFence != Fence::NO_FENCE) {
-            outString->append("- Retire\tNot signaled\n");
-        }
-
-        for (const auto& kv : frame.layers) {
-            const LayerRecord& layer = kv.second;
-            outString->appendFormat("-- %s\n", layer.name.string());
-            outString->appendFormat("---- Frame # %" PRIu64 " (%s)\n",
-                    layer.frameNumber,
-                    layer.isGlesComposition ? "GLES" : "HWC");
-            outString->appendFormat("---- Req.Present.\t%" PRId64 "\n",
-                    layer.requestedPresentTime);
-            if (layer.acquireTime) {
-                outString->appendFormat("---- Acquire\t%" PRId64 "\n",
-                        layer.acquireTime);
-            } else {
-                outString->append("---- Acquire\tNot signaled\n");
-            }
-            if (layer.releaseTime) {
-                outString->appendFormat("---- Release\t%" PRId64 "\n",
-                        layer.releaseTime);
-            } else {
-                outString->append("---- Release\tNot signaled\n");
-            }
-        }
-    }
-}
-
-static inline bool isValidTimestamp(nsecs_t time) {
-    return time > 0 && time < INT64_MAX;
-}
-
-void FenceTracker::checkFencesForCompletion() {
-    ATRACE_CALL();
-    for (auto& frame : mFrames) {
-        if (frame.presentFence != Fence::NO_FENCE) {
-            nsecs_t time = frame.presentFence->getSignalTime();
-            if (isValidTimestamp(time)) {
-                frame.presentTime = time;
-                frame.presentFence = Fence::NO_FENCE;
-            }
-        }
-        if (frame.retireFence != Fence::NO_FENCE) {
-            nsecs_t time = frame.retireFence->getSignalTime();
-            if (isValidTimestamp(time)) {
-                frame.retireTime = time;
-                frame.retireFence = Fence::NO_FENCE;
-            }
-        }
-        if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
-            nsecs_t time = frame.glesCompositionDoneFence->getSignalTime();
-            if (isValidTimestamp(time)) {
-                frame.glesCompositionDoneTime = time;
-                frame.glesCompositionDoneFence = Fence::NO_FENCE;
-            }
-        }
-        for (auto& kv : frame.layers) {
-            LayerRecord& layer = kv.second;
-            if (layer.acquireFence != Fence::NO_FENCE) {
-                nsecs_t time = layer.acquireFence->getSignalTime();
-                if (isValidTimestamp(time)) {
-                    layer.acquireTime = time;
-                    layer.acquireFence = Fence::NO_FENCE;
-                }
-            }
-            if (layer.releaseFence != Fence::NO_FENCE) {
-                nsecs_t time = layer.releaseFence->getSignalTime();
-                if (isValidTimestamp(time)) {
-                    layer.releaseTime = time;
-                    layer.releaseFence = Fence::NO_FENCE;
-                }
-            }
-        }
-    }
-}
-
-void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> presentFence,
-        sp<Fence> retireFence, const Vector<sp<Layer>>& layers,
-        sp<Fence> glDoneFence) {
-    ATRACE_CALL();
-    Mutex::Autolock lock(mMutex);
-    FrameRecord& frame = mFrames[mOffset];
-    FrameRecord& prevFrame = mFrames[(mOffset + MAX_FRAME_HISTORY - 1) %
-                                     MAX_FRAME_HISTORY];
-    frame.layers.clear();
-
-    bool wasGlesCompositionDone = false;
-    const size_t count = layers.size();
-    for (size_t i = 0; i < count; i++) {
-        String8 name;
-        uint64_t frameNumber;
-        bool glesComposition;
-        nsecs_t requestedPresentTime;
-        sp<Fence> acquireFence;
-        sp<Fence> prevReleaseFence;
-        int32_t layerId = layers[i]->getSequence();
-
-        layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
-                &requestedPresentTime, &acquireFence, &prevReleaseFence);
-
-        frame.layers.emplace(std::piecewise_construct,
-                std::forward_as_tuple(layerId),
-                std::forward_as_tuple(name, frameNumber, glesComposition,
-                requestedPresentTime, 0, 0, acquireFence, Fence::NO_FENCE));
-        auto prevLayer = prevFrame.layers.find(layerId);
-        if (prevLayer != prevFrame.layers.end()) {
-            if (frameNumber != prevLayer->second.frameNumber) {
-               prevLayer->second.releaseFence = prevReleaseFence;
-            }
-        }
-    }
-
-    frame.frameId = mFrameCounter;
-    frame.refreshStartTime = refreshStartTime;
-    frame.presentTime = 0;
-    frame.retireTime = 0;
-    frame.glesCompositionDoneTime = 0;
-    frame.presentFence = presentFence;
-    prevFrame.retireFence = retireFence;
-    frame.retireFence = Fence::NO_FENCE;
-    frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence :
-            Fence::NO_FENCE;
-
-    mOffset = (mOffset + 1) % MAX_FRAME_HISTORY;
-    mFrameCounter++;
-}
-
-bool FenceTracker::getFrameTimestamps(const Layer& layer,
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
-    Mutex::Autolock lock(mMutex);
-    checkFencesForCompletion();
-    int32_t layerId = layer.getSequence();
-
-    size_t i = 0;
-    for (; i < MAX_FRAME_HISTORY; i++) {
-       if (mFrames[i].layers.count(layerId) &&
-               mFrames[i].layers[layerId].frameNumber == frameNumber) {
-           break;
-       }
-    }
-    if (i == MAX_FRAME_HISTORY) {
-        return false;
-    }
-
-    const FrameRecord& frameRecord = mFrames[i];
-    const LayerRecord& layerRecord = mFrames[i].layers[layerId];
-    outTimestamps->frameNumber = frameNumber;
-    outTimestamps->requestedPresentTime = layerRecord.requestedPresentTime;
-    outTimestamps->acquireTime = layerRecord.acquireTime;
-    outTimestamps->refreshStartTime = frameRecord.refreshStartTime;
-    outTimestamps->glCompositionDoneTime = frameRecord.glesCompositionDoneTime;
-    outTimestamps->displayPresentTime = frameRecord.presentTime;
-    outTimestamps->displayRetireTime = frameRecord.retireTime;
-    outTimestamps->releaseTime = layerRecord.releaseTime;
-    return true;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/FenceTracker.h b/services/surfaceflinger/FenceTracker.h
deleted file mode 100644
index 3b429d1..0000000
--- a/services/surfaceflinger/FenceTracker.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_FENCETRACKER_H
-#define ANDROID_FENCETRACKER_H
-
-#include <ui/Fence.h>
-#include <utils/Mutex.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <unordered_map>
-
-namespace android {
-
-class Layer;
-struct FrameTimestamps;
-/*
- * Keeps a circular buffer of fence/timestamp data for the last N frames in
- * SurfaceFlinger. Gets timestamps for fences after they have signaled.
- */
-class FenceTracker {
-public:
-     FenceTracker();
-     void dump(String8* outString);
-     void addFrame(nsecs_t refreshStartTime, sp<Fence> presentFence,
-             sp<Fence> retireFence, const Vector<sp<Layer>>& layers,
-             sp<Fence> glDoneFence);
-     bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
-             FrameTimestamps* outTimestamps);
-
-protected:
-     static constexpr size_t MAX_FRAME_HISTORY = 8;
-
-     struct LayerRecord {
-         String8 name; // layer name
-         uint64_t frameNumber; // frame number for this layer
-         bool isGlesComposition; // was GLES composition used for this layer?
-         // time the producer requested this frame be presented
-         nsecs_t requestedPresentTime;
-         nsecs_t acquireTime; // timestamp from the acquire fence
-         nsecs_t releaseTime; // timestamp from the release fence
-         sp<Fence> acquireFence; // acquire fence
-         sp<Fence> releaseFence; // release fence
-
-         LayerRecord(const String8& name, uint64_t frameNumber,
-                 bool isGlesComposition, nsecs_t requestedPresentTime,
-                 nsecs_t acquireTime, nsecs_t releaseTime,
-                 sp<Fence> acquireFence, sp<Fence> releaseFence) :
-                 name(name), frameNumber(frameNumber),
-                 isGlesComposition(isGlesComposition),
-                 requestedPresentTime(requestedPresentTime),
-                 acquireTime(acquireTime), releaseTime(releaseTime),
-                 acquireFence(acquireFence), releaseFence(releaseFence) {};
-         LayerRecord() : name("uninitialized"), frameNumber(0),
-                 isGlesComposition(false), requestedPresentTime(0),
-                 acquireTime(0), releaseTime(0), acquireFence(Fence::NO_FENCE),
-                 releaseFence(Fence::NO_FENCE) {};
-     };
-
-     struct FrameRecord {
-         // global SurfaceFlinger frame counter
-         uint64_t frameId;
-         // layer data for this frame
-         std::unordered_map<int32_t, LayerRecord> layers;
-         // timestamp for when SurfaceFlinger::handleMessageRefresh() was called
-         nsecs_t refreshStartTime;
-         // timestamp from the present fence
-         nsecs_t presentTime;
-         // timestamp from the retire fence
-         nsecs_t retireTime;
-         // timestamp from the GLES composition completion fence
-         nsecs_t glesCompositionDoneTime;
-         // primary display present fence for this frame
-         sp<Fence> presentFence;
-         // primary display retire fence for this frame
-         sp<Fence> retireFence;
-         // if GLES composition was done, the fence for its completion
-         sp<Fence> glesCompositionDoneFence;
-
-         FrameRecord() : frameId(0), layers(), refreshStartTime(0),
-                 presentTime(0), retireTime(0), glesCompositionDoneTime(0),
-                 presentFence(Fence::NO_FENCE), retireFence(Fence::NO_FENCE),
-                 glesCompositionDoneFence(Fence::NO_FENCE) {}
-     };
-
-     uint64_t mFrameCounter;
-     uint32_t mOffset;
-     FrameRecord mFrames[MAX_FRAME_HISTORY];
-     Mutex mMutex;
-
-     void checkFencesForCompletion();
-};
-
-}
-
-#endif // ANDROID_FRAMETRACKER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4772fc1..c16af59 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -80,7 +80,9 @@
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mOverrideScalingMode(-1),
         mCurrentOpacity(true),
+        mBufferLatched(false),
         mCurrentFrameNumber(0),
+        mPreviousFrameNumber(-1U),
         mRefreshPending(false),
         mFrameLatencyNeeded(false),
         mFiltering(false),
@@ -1729,14 +1731,53 @@
     return isDue || !isPlausible;
 }
 
-bool Layer::onPreComposition() {
+bool Layer::onPreComposition(nsecs_t refreshStartTime) {
+    if (mBufferLatched) {
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
+    }
     mRefreshPending = false;
     return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
 }
 
-bool Layer::onPostComposition() {
+bool Layer::onPostComposition(sp<Fence> glDoneFence) {
+    // mFrameLatencyNeeded is true when a new frame was latched for the
+    // composition.
     bool frameLatencyNeeded = mFrameLatencyNeeded;
     if (mFrameLatencyNeeded) {
+        const HWComposer& hwc = mFlinger->getHwComposer();
+#ifdef USE_HWC2
+        sp<Fence> retireFence = Fence::NO_FENCE;
+        sp<Fence> presentFence = Fence::NO_FENCE;
+        sp<Fence> presentOrRetireFence = Fence::NO_FENCE;
+        if (hwc.retireFenceRepresentsStartOfScanout()) {
+            presentFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY);
+            presentOrRetireFence = presentFence;
+        } else {
+            retireFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY);
+            presentOrRetireFence = retireFence;
+        }
+        bool wasGpuComposited = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ?
+                mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType ==
+                HWC2::Composition::Client : true;
+#else
+        sp<Fence> retireFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
+        sp<Fence> presentFence = Fence::NO_FENCE;
+        sp<Fence> presentOrRetireFence = retireFence;
+        bool wasGpuComposited = mIsGlesComposition;
+#endif
+
+        // Update mFrameEventHistory.
+        {
+            Mutex::Autolock lock(mFrameEventHistoryMutex);
+            mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
+                    wasGpuComposited ? glDoneFence : Fence::NO_FENCE,
+                    presentFence);
+            mFrameEventHistory.addRetire(mPreviousFrameNumber,
+                    retireFence);
+        }
+
+        // Update mFrameTracker.
         nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
         mFrameTracker.setDesiredPresentTime(desiredPresentTime);
 
@@ -1749,14 +1790,8 @@
             mFrameTracker.setFrameReadyTime(desiredPresentTime);
         }
 
-        const HWComposer& hwc = mFlinger->getHwComposer();
-#ifdef USE_HWC2
-        sp<Fence> presentFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY);
-#else
-        sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
-#endif
-        if (presentFence->isValid()) {
-            mFrameTracker.setActualPresentFence(presentFence);
+        if (presentOrRetireFence->isValid()) {
+            mFrameTracker.setActualPresentFence(presentOrRetireFence);
         } else {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
@@ -1773,6 +1808,9 @@
 #ifdef USE_HWC2
 void Layer::releasePendingBuffer() {
     mSurfaceFlingerConsumer->releasePendingBuffer();
+    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    mFrameEventHistory.addRelease(mPreviousFrameNumber,
+            mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
 }
 #endif
 
@@ -1813,7 +1851,7 @@
     return !matchingFramesFound || allTransactionsApplied;
 }
 
-Region Layer::latchBuffer(bool& recomputeVisibleRegions)
+Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime)
 {
     ATRACE_CALL();
 
@@ -1937,6 +1975,19 @@
         return outDirtyRegion;
     }
 
+    mBufferLatched = true;
+    mPreviousFrameNumber = mCurrentFrameNumber;
+    mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+    {
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+#ifndef USE_HWC2
+        mFrameEventHistory.addRelease(mPreviousFrameNumber,
+                mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+#endif
+    }
+
     mRefreshPending = true;
     mFrameLatencyNeeded = true;
     if (oldActiveBuffer == NULL) {
@@ -1972,8 +2023,6 @@
         recomputeVisibleRegions = true;
     }
 
-    mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
     // Remove any sync points corresponding to the buffer which was just
     // latched
     {
@@ -2158,22 +2207,32 @@
     mFrameTracker.getStats(outStats);
 }
 
-void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber,
-        bool* outIsGlesComposition, nsecs_t* outRequestedPresentTime,
-        sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const {
-    *outName = mName;
-    *outFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+void Layer::dumpFrameEvents(String8& result) {
+    result.appendFormat("- Layer %s (%s, %p)\n",
+            getName().string(), getTypeId(), this);
+    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    mFrameEventHistory.checkFencesForCompletion();
+    mFrameEventHistory.dump(result);
+}
 
-#ifdef USE_HWC2
-    *outIsGlesComposition = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ?
-            mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType ==
-            HWC2::Composition::Client : true;
-#else
-    *outIsGlesComposition = mIsGlesComposition;
-#endif
-    *outRequestedPresentTime = mSurfaceFlingerConsumer->getTimestamp();
-    *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence();
-    *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevFinalReleaseFence();
+bool Layer::addAndGetFrameTimestamps(
+        const NewFrameEventsEntry* newTimestamps,
+        uint64_t frameNumber, FrameTimestamps *outTimestamps) {
+    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;
+        }
+    }
+
+    return false;
 }
 
 std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory(
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5aba69b..98ea053 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -270,13 +270,13 @@
      * called before composition.
      * returns true if the layer has pending updates.
      */
-    bool onPreComposition();
+    bool onPreComposition(nsecs_t refreshStartTime);
 
     /*
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
      */
-    bool onPostComposition();
+    bool onPostComposition(sp<Fence> glCompositionDoneFence);
 
 #ifdef USE_HWC2
     // If a buffer was replaced this frame, release the former buffer
@@ -323,7 +323,7 @@
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    Region latchBuffer(bool& recomputeVisibleRegions);
+    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
 
     bool isPotentialCursor() const { return mPotentialCursor;}
 
@@ -402,20 +402,17 @@
     void miniDump(String8& result, int32_t hwcId) const;
 #endif
     void dumpFrameStats(String8& result) const;
+    void dumpFrameEvents(String8& result);
     void clearFrameStats();
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
 
-    void getFenceData(String8* outName, uint64_t* outFrameNumber,
-            bool* outIsGlesComposition, nsecs_t* outRequestedPresentTime,
-            sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const;
 
     std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
 
-    bool getFrameTimestamps(uint64_t frameNumber,
-            FrameTimestamps* outTimestamps) const {
-        return mFlinger->getFrameTimestamps(*this, frameNumber, outTimestamps);
-    }
+    bool addAndGetFrameTimestamps(
+            const NewFrameEventsEntry* newTimestamps,
+            uint64_t frameNumber, FrameTimestamps* outTimestamps);
 
     bool getTransformToDisplayInverse() const;
 
@@ -583,8 +580,15 @@
     // thread-safe
     volatile int32_t mQueuedFrames;
     volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
+
+    // Timestamp history for UIAutomation. Thread safe.
     FrameTracker mFrameTracker;
 
+    // Timestamp history for the consumer to query.
+    // Accessed by both consumer and producer on main and binder threads.
+    Mutex mFrameEventHistoryMutex;
+    FrameEventHistory mFrameEventHistory;
+
     // main thread
     sp<GraphicBuffer> mActiveBuffer;
     sp<NativeHandle> mSidebandStream;
@@ -594,7 +598,9 @@
     // We encode unset as -1.
     int32_t mOverrideScalingMode;
     bool mCurrentOpacity;
+    bool mBufferLatched = false;  // TODO: Use mActiveBuffer?
     std::atomic<uint64_t> mCurrentFrameNumber;
+    uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
     bool mRefreshPending;
     bool mFrameLatencyNeeded;
     // Whether filtering is forced on or not
@@ -644,7 +650,7 @@
     Condition mQueueItemCondition;
     Vector<BufferItem> mQueueItems;
     std::atomic<uint64_t> mLastFrameNumberReceived;
-    bool mUpdateTexImageFailed; // This is only modified from the main thread
+    bool mUpdateTexImageFailed; // This is only accessed on the main thread.
 
     bool mAutoRefresh;
     bool mFreezePositionUpdates;
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index ffaee7a..4604e01 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -145,6 +145,11 @@
             outTransformMatrix);
 }
 
+bool MonitoredProducer::getFrameTimestamps(
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+    return mProducer->getFrameTimestamps(frameNumber, outTimestamps);
+}
+
 status_t MonitoredProducer::getUniqueId(uint64_t* outId) const {
     return mProducer->getUniqueId(outId);
 }
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 66f6cf0..5a2351f 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -63,6 +63,8 @@
     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 status_t getUniqueId(uint64_t* outId) const override;
 
 private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2f273ae..8400136 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1132,12 +1132,12 @@
 
     nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    preComposition();
+    preComposition(refreshStartTime);
     rebuildLayerStacks();
     setUpHWComposer();
     doDebugFlashRegions();
     doComposition();
-    postComposition(refreshStartTime);
+    postComposition();
 
     mPreviousPresentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
 
@@ -1195,7 +1195,7 @@
     }
 }
 
-void SurfaceFlinger::preComposition()
+void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
     ALOGV("preComposition");
@@ -1204,7 +1204,7 @@
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        if (layers[i]->onPreComposition()) {
+        if (layers[i]->onPreComposition(refreshStartTime)) {
             needExtraInvalidate = true;
         }
     }
@@ -1213,7 +1213,7 @@
     }
 }
 
-void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::postComposition()
 {
     ATRACE_CALL();
     ALOGV("postComposition");
@@ -1223,10 +1223,16 @@
         layer->releasePendingBuffer();
     }
 
+    bool hadClientComposition = mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY);
+
+    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+    sp<Fence> glCompositionDoneFence = hadClientComposition
+                                     ? hw->getClientTargetAcquireFence()
+                                     : Fence::NO_FENCE;
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        bool frameLatched = layers[i]->onPostComposition();
+        bool frameLatched = layers[i]->onPostComposition(glCompositionDoneFence);
         if (frameLatched) {
             recordBufferingStats(layers[i]->getName().string(),
                     layers[i]->getOccupancyHistory(false));
@@ -1243,26 +1249,12 @@
         }
     }
 
-    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
     if (kIgnorePresentFences) {
         if (hw->isDisplayOn()) {
             enableHardwareVsync();
         }
     }
 
-    sp<Fence> fenceTrackerPresentFence;
-    sp<Fence> fenceTrackerRetireFence;
-    if (mHwc->retireFenceRepresentsStartOfScanout()) {
-        fenceTrackerPresentFence = presentFence;
-        fenceTrackerRetireFence = Fence::NO_FENCE;
-    } else {
-        fenceTrackerPresentFence = Fence::NO_FENCE;
-        fenceTrackerRetireFence = presentFence;
-    }
-    mFenceTracker.addFrame(refreshStartTime,
-            fenceTrackerPresentFence, fenceTrackerRetireFence,
-            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
-
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
@@ -2019,6 +2011,7 @@
 {
     ALOGV("handlePageFlip");
 
+    nsecs_t latchTime = systemTime();
     Region dirtyRegion;
 
     bool visibleRegions = false;
@@ -2048,7 +2041,7 @@
         }
     }
     for (auto& layer : mLayersWithQueuedFrames) {
-        const Region dirty(layer->latchBuffer(visibleRegions));
+        const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
         layer->useSurfaceDamage();
         const Layer::State& s(layer->getDrawingState());
         invalidateLayerStack(s.layerStack, dirty);
@@ -2845,9 +2838,9 @@
             }
 
             if ((index < numArgs) &&
-                    (args[index] == String16("--fences"))) {
+                    (args[index] == String16("--frame-events"))) {
                 index++;
-                mFenceTracker.dump(&result);
+                dumpFrameEventsLocked(result);
                 dumpAll = false;
             }
         }
@@ -2988,6 +2981,16 @@
     }
 }
 
+void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
+    result.appendFormat("Layer frame timestamps:\n");
+
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        currentLayers[i]->dumpFrameEvents(result);
+    }
+}
+
 void SurfaceFlinger::dumpBufferingStats(String8& result) const {
     result.append("Buffering stats:\n");
     result.append("  [Layer name] <Active time> <Two buffer> "
@@ -3907,11 +3910,6 @@
     }
 }
 
-bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
-    return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
-}
-
 // ---------------------------------------------------------------------------
 
 SurfaceFlinger::LayerVector::LayerVector() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bdb2614..5b216dd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -53,7 +53,6 @@
 #include "Barrier.h"
 #include "DisplayDevice.h"
 #include "DispSync.h"
-#include "FenceTracker.h"
 #include "FrameTracker.h"
 #include "MessageQueue.h"
 #include "SurfaceInterceptor.h"
@@ -401,8 +400,8 @@
             const LayerVector& currentLayers, uint32_t layerStack,
             Region& dirtyRegion, Region& opaqueRegion);
 
-    void preComposition();
-    void postComposition(nsecs_t refreshStartTime);
+    void preComposition(nsecs_t refreshStartTime);
+    void postComposition();
     void rebuildLayerStacks();
     void setUpHWComposer();
     void doComposition();
@@ -446,14 +445,13 @@
     void logFrameStats();
 
     void dumpStaticScreenStats(String8& result) const;
+    // Not const because each Layer needs to query Fences and cache timestamps.
+    void dumpFrameEventsLocked(String8& result);
 
     void recordBufferingStats(const char* layerName,
             std::vector<OccupancyTracker::Segment>&& history);
     void dumpBufferingStats(String8& result) const;
 
-    bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
-            FrameTimestamps* outTimestamps);
-
     /* ------------------------------------------------------------------------
      * Attributes
      */
@@ -519,7 +517,6 @@
     nsecs_t mLastTransactionTime;
     bool mBootFinished;
     bool mForceFullDamage;
-    FenceTracker mFenceTracker;
 #ifdef USE_HWC2
     bool mPropagateBackpressure = true;
 #endif
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 5317cc7..1ef7065 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -248,10 +248,15 @@
     }
 }
 
-bool SurfaceFlingerConsumer::getFrameTimestamps(uint64_t frameNumber,
-        FrameTimestamps* outTimestamps) const {
-    sp<const Layer> l = mLayer.promote();
-    return l.get() ? l->getFrameTimestamps(frameNumber, outTimestamps) : false;
+bool SurfaceFlingerConsumer::addAndGetFrameTimestamps(
+        const NewFrameEventsEntry* newTimestamps,
+        uint64_t frameNumber, FrameTimestamps *outTimestamps) {
+    sp<Layer> l = mLayer.promote();
+    if (!l.get()) {
+        return false;
+    }
+    return l->addAndGetFrameTimestamps(
+            newTimestamps, frameNumber, outTimestamps);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index cb4c334..0f46ddc 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -37,7 +37,7 @@
     };
 
     SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
-            uint32_t tex, const Layer* layer)
+            uint32_t tex, Layer* layer)
         : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
           mTransformToDisplayInverse(false), mSurfaceDamage(), mLayer(layer)
     {}
@@ -84,8 +84,9 @@
     void releasePendingBuffer();
 #endif
 
-    virtual bool getFrameTimestamps(uint64_t frameNumber,
-            FrameTimestamps* outTimestamps) const override;
+    virtual bool addAndGetFrameTimestamps(
+            const NewFrameEventsEntry* newTimestamps,
+            uint64_t frameNumber, FrameTimestamps* outTimestamps) override;
 
 private:
     virtual void onSidebandStreamChanged();
@@ -107,7 +108,7 @@
 #endif
 
     // The layer for this SurfaceFlingerConsumer
-    wp<const Layer> mLayer;
+    const wp<Layer> mLayer;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0143d99..3bdb021 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -1068,12 +1068,12 @@
 
     nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    preComposition();
+    preComposition(refreshStartTime);
     rebuildLayerStacks();
     setUpHWComposer();
     doDebugFlashRegions();
     doComposition();
-    postComposition(refreshStartTime);
+    postComposition();
 }
 
 void SurfaceFlinger::doDebugFlashRegions()
@@ -1116,13 +1116,13 @@
     }
 }
 
-void SurfaceFlinger::preComposition()
+void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
 {
     bool needExtraInvalidate = false;
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        if (layers[i]->onPreComposition()) {
+        if (layers[i]->onPreComposition(refreshStartTime)) {
             needExtraInvalidate = true;
         }
     }
@@ -1131,19 +1131,28 @@
     }
 }
 
-void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::postComposition()
 {
+    const HWComposer& hwc = getHwComposer();
+    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+
+    bool hadGlesComposition =
+            getHwComposer().hasGlesComposition(hw->getHwcDisplayId());
+    sp<Fence> glCompositionDoneFence = hadGlesComposition
+                                     ? hw->getClientTargetAcquireFence()
+                                     : Fence::NO_FENCE;
+
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        bool frameLatched = layers[i]->onPostComposition();
+        bool frameLatched = layers[i]->onPostComposition(
+                glCompositionDoneFence);
         if (frameLatched) {
             recordBufferingStats(layers[i]->getName().string(),
                     layers[i]->getOccupancyHistory(false));
         }
     }
 
-    const HWComposer& hwc = getHwComposer();
     sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
 
     if (presentFence->isValid()) {
@@ -1154,17 +1163,12 @@
         }
     }
 
-    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
     if (kIgnorePresentFences) {
         if (hw->isDisplayOn()) {
             enableHardwareVsync();
         }
     }
 
-    // The present fence is actually a retire fence in HWC1.
-    mFenceTracker.addFrame(refreshStartTime, Fence::NO_FENCE, presentFence,
-            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
-
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
@@ -1932,6 +1936,7 @@
 
 bool SurfaceFlinger::handlePageFlip()
 {
+    nsecs_t latchTime = systemTime();
     Region dirtyRegion;
 
     bool visibleRegions = false;
@@ -1963,7 +1968,7 @@
     }
     for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
         Layer* layer = layersWithQueuedFrames[i];
-        const Region dirty(layer->latchBuffer(visibleRegions));
+        const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
         layer->useSurfaceDamage();
         const Layer::State& s(layer->getDrawingState());
         invalidateLayerStack(s.layerStack, dirty);
@@ -2755,9 +2760,9 @@
             }
 
             if ((index < numArgs) &&
-                    (args[index] == String16("--fences"))) {
+                    (args[index] == String16("--frame-events"))) {
                 index++;
-                mFenceTracker.dump(&result);
+                dumpFrameEventsLocked(result);
                 dumpAll = false;
             }
         }
@@ -2880,6 +2885,16 @@
             NUM_BUCKETS - 1, bucketTimeSec, percent);
 }
 
+void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
+    result.appendFormat("Layer frame timestamps:\n");
+
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        currentLayers[i]->dumpFrameEvents(result);
+    }
+}
+
 void SurfaceFlinger::recordBufferingStats(const char* layerName,
         std::vector<OccupancyTracker::Segment>&& history) {
     Mutex::Autolock lock(mBufferingStatsMutex);
@@ -3754,11 +3769,6 @@
     return result;
 }
 
-bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
-    return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
-}
-
 void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
         const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) {
     if (DEBUG_SCREENSHOTS) {