SF: Add FenceTracker

FenceTracker tracks all fences in SurfaceFlinger. These timestamps
could be used for debugging, profiling, or be exposed to the
application.

Change-Id: I4297a661c0a7530e744168ac7a2a66c4bca92fd5
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 8cc9fc1..d0a0401 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -10,6 +10,7 @@
     DispSync.cpp \
     EventControlThread.cpp \
     EventThread.cpp \
+    FenceTracker.cpp \
     FrameTracker.cpp \
     Layer.cpp \
     LayerDim.cpp \
@@ -103,7 +104,7 @@
 endif
 
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
-LOCAL_CFLAGS += -std=c++11
+LOCAL_CFLAGS += -std=c++14
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -133,7 +134,7 @@
 
 LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++11
+LOCAL_CPPFLAGS := -std=c++14
 
 LOCAL_INIT_RC := surfaceflinger.rc
 
@@ -172,7 +173,7 @@
 LOCAL_CLANG := true
 
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++11
+LOCAL_CPPFLAGS := -std=c++14
 
 LOCAL_SRC_FILES := \
     DdmConnection.cpp
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 8d8e40d..f7c8473 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -364,11 +364,9 @@
         false, Transform::ROT_0);
 }
 
-#ifdef USE_HWC2
 const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
     return mDisplaySurface->getClientTargetAcquireFence();
 }
-#endif
 
 // ----------------------------------------------------------------------------
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 38241d9..9ac8a97 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -49,9 +49,7 @@
 
 struct DisplayInfo;
 class DisplaySurface;
-#ifdef USE_HWC2
 class Fence;
-#endif
 class IGraphicBufferProducer;
 class Layer;
 class SurfaceFlinger;
@@ -174,9 +172,7 @@
     EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const;
     void setViewportAndProjection() const;
 
-#ifdef USE_HWC2
     const sp<Fence>& getClientTargetAcquireFence() const;
-#endif
 
     /* ------------------------------------------------------------------------
      * Display power mode management.
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index d819f83..d801bb3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -76,9 +76,7 @@
 
     virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
 
-#ifdef USE_HWC2
     virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
-#endif
 
 protected:
     DisplaySurface() {}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 29e0766..7368d77 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -60,15 +60,14 @@
     ConsumerBase(consumer),
     mDisplayType(disp),
     mCurrentBufferSlot(-1),
-#ifdef USE_HWC2
     mCurrentBuffer(),
     mCurrentFence(Fence::NO_FENCE),
+#ifdef USE_HWC2
     mHwc(hwc),
     mHasPendingRelease(false),
     mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
     mPreviousBuffer()
 #else
-    mCurrentBuffer(0),
     mHwc(hwc)
 #endif
 {
@@ -168,9 +167,7 @@
     }
     mCurrentBufferSlot = item.mSlot;
     mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
-#ifdef USE_HWC2
     mCurrentFence = item.mFence;
-#endif
 
     outFence = item.mFence;
     outBuffer = mCurrentBuffer;
@@ -254,11 +251,9 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
-#ifdef USE_HWC2
 const sp<Fence>& FramebufferSurface::getClientTargetAcquireFence() const {
     return mCurrentFence;
 }
-#endif
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0605602..439435a 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -52,9 +52,7 @@
     // displays.
     virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
 
-#ifdef USE_HWC2
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
-#endif
 
 private:
     virtual ~FramebufferSurface() { }; // this class cannot be overloaded
@@ -88,10 +86,8 @@
     // no current buffer.
     sp<GraphicBuffer> mCurrentBuffer;
 
-#ifdef USE_HWC2
     // mCurrentFence is the current buffer's acquire fence
     sp<Fence> mCurrentFence;
-#endif
 
     // Hardware composer, owned by SurfaceFlinger.
     HWComposer& mHwc;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1afed36..ee4bf02 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -311,11 +311,9 @@
     mSinkBufferHeight = h;
 }
 
-#ifdef USE_HWC2
 const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const {
     return mFbFence;
 }
-#endif
 
 status_t VirtualDisplaySurface::requestBuffer(int pslot,
         sp<GraphicBuffer>* outBuf) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index fe187c2..cfa4e4c 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -90,9 +90,7 @@
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
     virtual void resizeBuffers(const uint32_t w, const uint32_t h);
-#ifdef USE_HWC2
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
-#endif
 
 private:
     enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
new file mode 100644
index 0000000..7da1d93
--- /dev/null
+++ b/services/surfaceflinger/FenceTracker.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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 <inttypes.h>
+#include "FenceTracker.h"
+#include "Layer.h"
+
+namespace android {
+
+FenceTracker::FenceTracker() :
+        mFrameCounter(0),
+        mOffset(0),
+        mFrames() {}
+
+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.retireTime) {
+            outString->appendFormat("- Retire\t%" PRId64 "\n",
+                    frame.retireTime);
+        } else {
+            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("---- Posted\t%" PRId64 "\n",
+                    layer.postedTime);
+            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() {
+    for (auto& frame : mFrames) {
+        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> retireFence,
+        const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence) {
+    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 postedTime;
+        sp<Fence> acquireFence;
+        sp<Fence> prevReleaseFence;
+        int32_t key = layers[i]->getSequence();
+
+        layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
+                &postedTime, &acquireFence, &prevReleaseFence);
+#ifdef USE_HWC2
+        if (glesComposition) {
+            frame.layers.emplace(std::piecewise_construct,
+                    std::forward_as_tuple(key),
+                    std::forward_as_tuple(name, frameNumber, glesComposition,
+                    postedTime, 0, 0, acquireFence, prevReleaseFence));
+            wasGlesCompositionDone = true;
+        } else {
+            frame.layers.emplace(std::piecewise_construct,
+                    std::forward_as_tuple(key),
+                    std::forward_as_tuple(name, frameNumber, glesComposition,
+                    postedTime, 0, 0, acquireFence, Fence::NO_FENCE));
+
+            auto prevLayer = prevFrame.layers.find(key);
+            if (prevLayer != prevFrame.layers.end()) {
+                prevLayer->second.releaseFence = prevReleaseFence;
+            }
+        }
+#else
+        frame.layers.emplace(std::piecewise_construct,
+                std::forward_as_tuple(key),
+                std::forward_as_tuple(name, frameNumber, glesComposition,
+                postedTime, 0, 0, acquireFence,
+                glesComposition ? Fence::NO_FENCE : prevReleaseFence));
+        if (glesComposition) {
+            wasGlesCompositionDone = true;
+        }
+#endif
+        frame.layers.emplace(std::piecewise_construct,
+                std::forward_as_tuple(key),
+                std::forward_as_tuple(name, frameNumber, glesComposition,
+                postedTime, 0, 0, acquireFence, prevReleaseFence));
+    }
+
+    frame.frameId = mFrameCounter;
+    frame.refreshStartTime = refreshStartTime;
+    frame.retireTime = 0;
+    frame.glesCompositionDoneTime = 0;
+    prevFrame.retireFence = retireFence;
+    frame.retireFence = Fence::NO_FENCE;
+    frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence :
+            Fence::NO_FENCE;
+
+    mOffset = (mOffset + 1) % MAX_FRAME_HISTORY;
+    mFrameCounter++;
+
+    checkFencesForCompletion();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FenceTracker.h b/services/surfaceflinger/FenceTracker.h
new file mode 100644
index 0000000..de99820
--- /dev/null
+++ b/services/surfaceflinger/FenceTracker.h
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+/*
+ * 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> retireFence,
+             const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence);
+
+protected:
+     static constexpr size_t MAX_FRAME_HISTORY = 128;
+
+     struct LayerRecord {
+         String8 name; // layer name
+         uint64_t frameNumber; // frame number for this layer
+         bool isGlesComposition; // was GLES composition used for this layer?
+         nsecs_t postedTime; // time when buffer was queued
+         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 postedTime,
+                 nsecs_t acquireTime, nsecs_t releaseTime,
+                 sp<Fence> acquireFence, sp<Fence> releaseFence) :
+                 name(name), frameNumber(frameNumber),
+                 isGlesComposition(isGlesComposition), postedTime(postedTime),
+                 acquireTime(acquireTime), releaseTime(releaseTime),
+                 acquireFence(acquireFence), releaseFence(releaseFence) {};
+         LayerRecord() : name("uninitialized"), frameNumber(0),
+                 isGlesComposition(false), postedTime(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 retire fence
+         nsecs_t retireTime;
+         // timestamp from the GLES composition completion fence
+         nsecs_t glesCompositionDoneTime;
+         // 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),
+                 retireTime(0), glesCompositionDoneTime(0),
+                 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 42d0810..cde92e9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -82,6 +82,9 @@
         mFiltering(false),
         mNeedsFiltering(false),
         mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
+#ifndef USE_HWC2
+        mIsGlesComposition(false),
+#endif
         mProtectedByApp(false),
         mHasSurface(false),
         mClientRef(client),
@@ -750,6 +753,7 @@
     Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
     layer.setVisibleRegionScreen(visible);
     layer.setSurfaceDamage(surfaceDamageRegion);
+    mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER);
 
     if (mSidebandStream.get()) {
         layer.setSidebandStream(mSidebandStream);
@@ -2046,6 +2050,23 @@
     mFrameTracker.getStats(outStats);
 }
 
+void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber,
+        bool* outIsGlesComposition, nsecs_t* outPostedTime,
+        sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const {
+    *outName = mName;
+    *outFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+#ifdef USE_HWC2
+    *outIsGlesComposition = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ?
+            mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType ==
+            HWC2::Composition::Client : true;
+#else
+    *outIsGlesComposition = mIsGlesComposition;
+#endif
+    *outPostedTime = mSurfaceFlingerConsumer->getTimestamp();
+    *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+    *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevReleaseFence();
+}
 // ---------------------------------------------------------------------------
 
 Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b0088e6..d5c84b6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -177,6 +177,8 @@
     sp<IGraphicBufferProducer> getProducer() const;
     const String8& getName() const;
 
+    int32_t getSequence() const { return sequence; }
+
     // -----------------------------------------------------------------------
     // Virtuals
 
@@ -396,6 +398,10 @@
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
 
+    void getFenceData(String8* outName, uint64_t* outFrameNumber,
+            bool* outIsGlesComposition, nsecs_t* outPostedTime,
+            sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const;
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -555,6 +561,8 @@
         bool clearClientTarget;
     };
     std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+#else
+    bool mIsGlesComposition;
 #endif
 
     // page-flip thread (currently main thread)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3a0e21f..d1cb1be 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -910,6 +910,7 @@
 void SurfaceFlinger::handleMessageRefresh() {
     ATRACE_CALL();
 
+    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
     static nsecs_t previousExpectedPresent = 0;
     nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
     static bool previousFrameMissed = false;
@@ -930,7 +931,7 @@
         setUpHWComposer();
         doDebugFlashRegions();
         doComposition();
-        postComposition();
+        postComposition(refreshStartTime);
     }
 
     // Release any buffers which were replaced this frame
@@ -999,7 +1000,7 @@
     }
 }
 
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
     ALOGV("postComposition");
@@ -1027,6 +1028,9 @@
         }
     }
 
+    mFenceTracker.addFrame(refreshStartTime, presentFence,
+            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
@@ -2539,6 +2543,13 @@
                 dumpStaticScreenStats(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--fences"))) {
+                index++;
+                mFenceTracker.dump(&result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7d6f139..37110b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -50,6 +50,7 @@
 #include "Barrier.h"
 #include "DisplayDevice.h"
 #include "DispSync.h"
+#include "FenceTracker.h"
 #include "FrameTracker.h"
 #include "MessageQueue.h"
 
@@ -384,7 +385,7 @@
             Region& dirtyRegion, Region& opaqueRegion);
 
     void preComposition();
-    void postComposition();
+    void postComposition(nsecs_t refreshStartTime);
     void rebuildLayerStacks();
     void setUpHWComposer();
     void doComposition();
@@ -488,6 +489,7 @@
     nsecs_t mLastTransactionTime;
     bool mBootFinished;
     bool mForceFullDamage;
+    FenceTracker mFenceTracker;
 
     // these are thread safe
     mutable MessageQueue mEventQueue;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 4c80fa0..c71b3bc 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -190,6 +190,7 @@
 #ifdef USE_HWC2
 void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence)
 {
+    mPrevReleaseFence = fence;
     if (!mPendingRelease.isPending) {
         GLConsumer::setReleaseFence(fence);
         return;
@@ -219,8 +220,17 @@
             strerror(-result), result);
     mPendingRelease = PendingRelease();
 }
+#else
+void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence) {
+    mPrevReleaseFence = fence;
+    GLConsumer::setReleaseFence(fence);
+}
 #endif
 
+sp<Fence> SurfaceFlingerConsumer::getPrevReleaseFence() const {
+    return mPrevReleaseFence;
+}
+
 void SurfaceFlingerConsumer::setContentsChangedListener(
         const wp<ContentsChangedListener>& listener) {
     setFrameAvailableListener(listener);
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index f40d53e..51b002f 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -37,7 +37,8 @@
     SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
             uint32_t tex)
         : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
-          mTransformToDisplayInverse(false), mSurfaceDamage()
+          mTransformToDisplayInverse(false), mSurfaceDamage(),
+          mPrevReleaseFence(Fence::NO_FENCE)
     {}
 
     class BufferRejecter {
@@ -75,8 +76,9 @@
 
     nsecs_t computeExpectedPresent(const DispSync& dispSync);
 
-#ifdef USE_HWC2
     virtual void setReleaseFence(const sp<Fence>& fence) override;
+    sp<Fence> getPrevReleaseFence() const;
+#ifdef USE_HWC2
     void releasePendingBuffer();
 #endif
 
@@ -98,6 +100,9 @@
     // presentDisplay
     PendingRelease mPendingRelease;
 #endif
+
+    // The release fence of the already displayed buffer (previous frame).
+    sp<Fence> mPrevReleaseFence;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index d864874..6c68777 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -927,6 +927,7 @@
 void SurfaceFlinger::handleMessageRefresh() {
     ATRACE_CALL();
 
+    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
     static nsecs_t previousExpectedPresent = 0;
     nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
     static bool previousFrameMissed = false;
@@ -947,7 +948,7 @@
         setUpHWComposer();
         doDebugFlashRegions();
         doComposition();
-        postComposition();
+        postComposition(refreshStartTime);
     }
 
     previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
@@ -1008,7 +1009,7 @@
     }
 }
 
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
 {
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
@@ -1034,6 +1035,9 @@
         }
     }
 
+    mFenceTracker.addFrame(refreshStartTime, presentFence,
+            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
@@ -2577,6 +2581,13 @@
                 dumpStaticScreenStats(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--fences"))) {
+                index++;
+                mFenceTracker.dump(&result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {