Merge "SF: Create a cicular buffer structure to store layer information."
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9abb040..088c256 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -139,6 +139,7 @@
         "Scheduler/DispSyncSource.cpp",
         "Scheduler/EventControlThread.cpp",
         "Scheduler/EventThread.cpp",
+        "Scheduler/LayerHistory.cpp",
         "Scheduler/MessageQueue.cpp",
         "Scheduler/Scheduler.cpp",
         "StartPropertySetThread.cpp",
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
new file mode 100644
index 0000000..e944eb9
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 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 "LayerHistory.h"
+
+#include <cinttypes>
+#include <cstdint>
+#include <numeric>
+#include <string>
+#include <unordered_map>
+
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+LayerHistory::LayerHistory() {}
+
+LayerHistory::~LayerHistory() = default;
+
+void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) {
+    mElements[mCounter].insert(std::make_pair(layerName, presentTime));
+}
+
+void LayerHistory::incrementCounter() {
+    mCounter++;
+    mCounter = mCounter % ARRAY_SIZE;
+    mElements[mCounter].clear();
+}
+
+const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const {
+    return mElements.at(index);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
new file mode 100644
index 0000000..1a7f9cd
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#include <array>
+#include <cinttypes>
+#include <cstdint>
+#include <numeric>
+#include <string>
+#include <unordered_map>
+
+#include <utils/Timers.h>
+
+namespace android {
+
+/*
+ * This class represents a circular buffer in which we keep layer history for
+ * the past ARRAY_SIZE frames. Each time, a signal for new frame comes, the counter
+ * gets incremented and includes all the layers that are requested to draw in that
+ * frame.
+ *
+ * Once the buffer reaches the end of the array, it starts overriding the elements
+ * at the beginning of the array.
+ */
+class LayerHistory {
+public:
+    LayerHistory();
+    ~LayerHistory();
+
+    // Method for inserting layers and their requested present time into the ring buffer.
+    // The elements are going to be inserted into an unordered_map at the position of
+    // mCounter.
+    void insert(const std::string layerName, nsecs_t presentTime);
+    // Method for incrementing the current slot in the ring buffer. It also clears the
+    // unordered_map, if it was created previously.
+    void incrementCounter();
+    // Returns unordered_map at the given at index.
+    const std::unordered_map<std::string, nsecs_t>& get(size_t index) const;
+
+private:
+    size_t mCounter = 0;
+    static constexpr size_t ARRAY_SIZE = 30;
+    std::array<std::unordered_map<std::string, nsecs_t>, ARRAY_SIZE> mElements;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 6fe52d3..58f1e9c 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -29,6 +29,7 @@
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
         "EventThreadTest.cpp",
+        "LayerHistoryTest.cpp",
         "SchedulerTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockDisplaySurface.cpp",
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
new file mode 100644
index 0000000..b518f10
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -0,0 +1,144 @@
+#undef LOG_TAG
+#define LOG_TAG "LayerHistoryUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include <mutex>
+
+#include "Scheduler/LayerHistory.h"
+
+using testing::_;
+using testing::Return;
+
+namespace android {
+
+class LayerHistoryTest : public testing::Test {
+public:
+    LayerHistoryTest();
+    ~LayerHistoryTest() override;
+
+protected:
+    std::unique_ptr<LayerHistory> mLayerHistory;
+};
+
+LayerHistoryTest::LayerHistoryTest() {
+    mLayerHistory = std::make_unique<LayerHistory>();
+}
+LayerHistoryTest::~LayerHistoryTest() {}
+
+namespace {
+TEST_F(LayerHistoryTest, simpleInsertAndGet) {
+    mLayerHistory->insert("TestLayer", 0);
+
+    const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0);
+    EXPECT_EQ(1, testMap.size());
+    auto element = testMap.find("TestLayer");
+    EXPECT_EQ("TestLayer", element->first);
+    EXPECT_EQ(0, element->second);
+
+    // Testing accessing object at an empty container will return an empty map.
+    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1);
+    EXPECT_EQ(0, emptyMap.size());
+}
+
+TEST_F(LayerHistoryTest, multipleInserts) {
+    mLayerHistory->insert("TestLayer0", 0);
+    mLayerHistory->insert("TestLayer1", 1);
+    mLayerHistory->insert("TestLayer2", 2);
+    mLayerHistory->insert("TestLayer3", 3);
+
+    const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0);
+    // Because the counter was not incremented, all elements were inserted into the first
+    // container.
+    EXPECT_EQ(4, testMap.size());
+    auto element = testMap.find("TestLayer0");
+    EXPECT_EQ("TestLayer0", element->first);
+    EXPECT_EQ(0, element->second);
+
+    element = testMap.find("TestLayer1");
+    EXPECT_EQ("TestLayer1", element->first);
+    EXPECT_EQ(1, element->second);
+
+    element = testMap.find("TestLayer2");
+    EXPECT_EQ("TestLayer2", element->first);
+    EXPECT_EQ(2, element->second);
+
+    element = testMap.find("TestLayer3");
+    EXPECT_EQ("TestLayer3", element->first);
+    EXPECT_EQ(3, element->second);
+
+    // Testing accessing object at an empty container will return an empty map.
+    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1);
+    EXPECT_EQ(0, emptyMap.size());
+}
+
+TEST_F(LayerHistoryTest, incrementingCounter) {
+    mLayerHistory->insert("TestLayer0", 0);
+    mLayerHistory->incrementCounter();
+    mLayerHistory->insert("TestLayer1", 1);
+    mLayerHistory->insert("TestLayer2", 2);
+    mLayerHistory->incrementCounter();
+    mLayerHistory->insert("TestLayer3", 3);
+
+    // Because the counter was incremented, the elements were inserted into different
+    // containers.
+    const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
+    EXPECT_EQ(1, testMap1.size());
+    auto element = testMap1.find("TestLayer0");
+    EXPECT_EQ("TestLayer0", element->first);
+    EXPECT_EQ(0, element->second);
+
+    const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(1);
+    EXPECT_EQ(2, testMap2.size());
+    element = testMap2.find("TestLayer1");
+    EXPECT_EQ("TestLayer1", element->first);
+    EXPECT_EQ(1, element->second);
+    element = testMap2.find("TestLayer2");
+    EXPECT_EQ("TestLayer2", element->first);
+    EXPECT_EQ(2, element->second);
+
+    const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(2);
+    EXPECT_EQ(1, testMap3.size());
+    element = testMap3.find("TestLayer3");
+    EXPECT_EQ("TestLayer3", element->first);
+    EXPECT_EQ(3, element->second);
+
+    // Testing accessing object at an empty container will return an empty map.
+    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(3);
+    EXPECT_EQ(0, emptyMap.size());
+}
+
+TEST_F(LayerHistoryTest, clearTheMap) {
+    mLayerHistory->insert("TestLayer0", 0);
+    mLayerHistory->incrementCounter();
+
+    const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
+    EXPECT_EQ(1, testMap1.size());
+    auto element = testMap1.find("TestLayer0");
+    EXPECT_EQ("TestLayer0", element->first);
+    EXPECT_EQ(0, element->second);
+
+    // The array currently contains 30 elements.
+    for (int i = 1; i < 30; ++i) {
+        mLayerHistory->insert("TestLayer0", i);
+        mLayerHistory->incrementCounter();
+    }
+    // Expect the map to be cleared.
+    const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(0);
+    EXPECT_EQ(0, testMap2.size());
+
+    mLayerHistory->insert("TestLayer30", 30);
+    const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(0);
+    element = testMap3.find("TestLayer30");
+    EXPECT_EQ("TestLayer30", element->first);
+    EXPECT_EQ(30, element->second);
+    // The original element in this location does not exist anymore.
+    element = testMap3.find("TestLayer0");
+    EXPECT_EQ(testMap3.end(), element);
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file