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