Merge "Fix logical error in UID idle/active handling" into rvc-dev
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 6366529..3afbabf 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -33,7 +33,7 @@
     DECLARE_META_INTERFACE(SurfaceComposerClient)
 
     // flags for createSurface()
-    enum { // (keep in sync with Surface.java)
+    enum { // (keep in sync with SurfaceControl.java)
         eHidden = 0x00000004,
         eDestroyBackbuffer = 0x00000020,
         eSecure = 0x00000080,
@@ -42,6 +42,7 @@
         eProtectedByApp = 0x00000800,
         eProtectedByDRM = 0x00001000,
         eCursorWindow = 0x00002000,
+        eNoColorFill = 0x00004000,
 
         eFXSurfaceBufferQueue = 0x00000000,
         eFXSurfaceEffect = 0x00020000,
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e5b94e4..07be791 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -31,6 +31,7 @@
 #include "SurfaceInterceptor.h"
 
 #include "FrameTracer/FrameTracer.h"
+#include "Scheduler/LayerHistory.h"
 #include "TimeStats/TimeStats.h"
 
 namespace android {
@@ -399,7 +400,8 @@
     // Add this buffer from our internal queue tracker
     { // Autolock scope
         const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp;
-        mFlinger->mScheduler->recordLayerHistory(this, presentTime);
+        mFlinger->mScheduler->recordLayerHistory(this, presentTime,
+                                                 LayerHistory::LayerUpdateType::Buffer);
 
         Mutex::Autolock lock(mQueueItemLock);
         // Reset the frame number tracker when we receive the first buffer after
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a1ed6d7..4f8fc41 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -283,7 +283,8 @@
     desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime;
     mCurrentState.desiredPresentTime = desiredPresentTime;
 
-    mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime);
+    mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime,
+                                             LayerHistory::LayerUpdateType::Buffer);
 
     addFrameEvent(acquireFence, postTime, desiredPresentTime);
     return true;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5b9dbf2..5a4d9cd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -119,6 +119,13 @@
     mCurrentState.treeHasFrameRateVote = false;
     mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID;
 
+    if (args.flags & ISurfaceComposerClient::eNoColorFill) {
+        // Set an invalid color so there is no color fill.
+        mCurrentState.color.r = -1.0_hf;
+        mCurrentState.color.g = -1.0_hf;
+        mCurrentState.color.b = -1.0_hf;
+    }
+
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
 
@@ -1392,7 +1399,8 @@
     }
 
     // Activate the layer in Scheduler's LayerHistory
-    mFlinger->mScheduler->recordLayerHistory(this, systemTime());
+    mFlinger->mScheduler->recordLayerHistory(this, systemTime(),
+                                             LayerHistory::LayerUpdateType::SetFrameRate);
 
     mCurrentState.sequence++;
     mCurrentState.frameRate = frameRate;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 8958d9a..2925109 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -79,7 +79,8 @@
     mLayerInfos.emplace_back(layer, std::move(info));
 }
 
-void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
+void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
+                          LayerUpdateType /*updateType*/) {
     std::lock_guard lock(mLock);
 
     const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index d5bebf6..acd76b0 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -52,10 +52,18 @@
     // Sets the display size. Client is responsible for synchronization.
     virtual void setDisplayArea(uint32_t displayArea) = 0;
 
+    // Sets whether a config change is pending to be applied
     virtual void setConfigChangePending(bool pending) = 0;
 
+    // Represents which layer activity is recorded
+    enum class LayerUpdateType {
+        Buffer,       // a new buffer queued
+        AnimationTX,  // a new transaction with eAnimation flag set
+        SetFrameRate, // setFrameRate API was called
+    };
+
     // Marks the layer as active, and records the given state to its history.
-    virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
+    virtual void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) = 0;
 
     using Summary = std::vector<RefreshRateConfigs::LayerRequirement>;
 
@@ -83,7 +91,7 @@
     void setConfigChangePending(bool /*pending*/) override {}
 
     // Marks the layer as active, and records the given state to its history.
-    void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
+    void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) override;
 
     // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
     android::scheduler::LayerHistory::Summary summarize(nsecs_t now) override;
@@ -141,7 +149,7 @@
     void setConfigChangePending(bool pending) override { mConfigChangePending = pending; }
 
     // Marks the layer as active, and records the given state to its history.
-    void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
+    void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) override;
 
     // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
     android::scheduler::LayerHistory::Summary summarize(nsecs_t /*now*/) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index 6570b1a..316000c 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -99,7 +99,8 @@
     mLayerInfos.emplace_back(layer, std::move(info));
 }
 
-void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
+void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
+                            LayerUpdateType updateType) {
     std::lock_guard lock(mLock);
 
     const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
@@ -107,7 +108,7 @@
     LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
 
     const auto& info = it->second;
-    info->setLastPresentTime(presentTime, now, mConfigChangePending);
+    info->setLastPresentTime(presentTime, now, updateType, mConfigChangePending);
 
     // Activate layer if inactive.
     if (const auto end = activeLayers().end(); it >= end) {
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index 25dca39..82da007 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -35,18 +35,24 @@
         mLayerVote({defaultVote, 0.0f}) {}
 
 void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now,
-                                     bool pendingConfigChange) {
+                                     LayerUpdateType updateType, bool pendingConfigChange) {
     lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
 
     mLastUpdatedTime = std::max(lastPresentTime, now);
-
-    FrameTimeData frameTime = {.presetTime = lastPresentTime,
-                               .queueTime = mLastUpdatedTime,
-                               .pendingConfigChange = pendingConfigChange};
-
-    mFrameTimes.push_back(frameTime);
-    if (mFrameTimes.size() > HISTORY_SIZE) {
-        mFrameTimes.pop_front();
+    switch (updateType) {
+        case LayerUpdateType::AnimationTX:
+            mLastAnimationTime = std::max(lastPresentTime, now);
+            break;
+        case LayerUpdateType::SetFrameRate:
+        case LayerUpdateType::Buffer:
+            FrameTimeData frameTime = {.presetTime = lastPresentTime,
+                                       .queueTime = mLastUpdatedTime,
+                                       .pendingConfigChange = pendingConfigChange};
+            mFrameTimes.push_back(frameTime);
+            if (mFrameTimes.size() > HISTORY_SIZE) {
+                mFrameTimes.pop_front();
+            }
+            break;
     }
 }
 
@@ -81,6 +87,10 @@
     return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
 }
 
+bool LayerInfoV2::isAnimating(nsecs_t now) const {
+    return mLastAnimationTime >= getActiveLayerThreshold(now);
+}
+
 bool LayerInfoV2::hasEnoughDataForHeuristic() const {
     // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
     if (mFrameTimes.size() < 2) {
@@ -190,6 +200,11 @@
         return {mLayerVote.type, mLayerVote.fps};
     }
 
+    if (isAnimating(now)) {
+        ALOGV("%s is animating", mName.c_str());
+        return {LayerHistory::LayerVoteType::Max, 0};
+    }
+
     if (!isFrequent(now)) {
         ALOGV("%s is infrequent", mName.c_str());
         return {LayerHistory::LayerVoteType::Min, 0};
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 5f50d5a..9e6783f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -43,6 +43,8 @@
 
 // Stores history of present times and refresh rates for a layer.
 class LayerInfoV2 {
+    using LayerUpdateType = LayerHistory::LayerUpdateType;
+
     // Layer is considered frequent if the earliest value in the window of most recent present times
     // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
     // favor of a low refresh rate.
@@ -63,7 +65,8 @@
     // Records the last requested present time. It also stores information about when
     // the layer was last updated. If the present time is farther in the future than the
     // updated time, the updated time is the present time.
-    void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange);
+    void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
+                            bool pendingConfigChange);
 
     // Sets an explicit layer vote. This usually comes directly from the application via
     // ANativeWindow_setFrameRate API
@@ -107,6 +110,7 @@
     };
 
     bool isFrequent(nsecs_t now) const;
+    bool isAnimating(nsecs_t now) const;
     bool hasEnoughDataForHeuristic() const;
     std::optional<float> calculateRefreshRateIfPossible();
     std::pair<nsecs_t, bool> calculateAverageFrameTime() const;
@@ -121,6 +125,8 @@
 
     nsecs_t mLastUpdatedTime = 0;
 
+    nsecs_t mLastAnimationTime = 0;
+
     float mLastReportedRefreshRate = 0.0f;
 
     // Holds information about the layer vote
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 7c2af23..d874c53 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -417,9 +417,10 @@
     }
 }
 
-void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) {
+void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
+                                   LayerHistory::LayerUpdateType updateType) {
     if (mLayerHistory) {
-        mLayerHistory->record(layer, presentTime, systemTime());
+        mLayerHistory->record(layer, presentTime, systemTime(), updateType);
     }
 }
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 066e9ca..c519826 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -39,6 +39,7 @@
 namespace android {
 
 using namespace std::chrono_literals;
+using scheduler::LayerHistory;
 
 class DispSync;
 class FenceTime;
@@ -118,7 +119,7 @@
 
     // Layers are registered on creation, and unregistered when the weak reference expires.
     void registerLayer(Layer*);
-    void recordLayerHistory(Layer*, nsecs_t presentTime);
+    void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
     void setConfigChangePending(bool pending);
 
     // Detects content using layer history, and selects a matching refresh rate.
@@ -211,7 +212,7 @@
     std::unique_ptr<EventControlThread> mEventControlThread;
 
     // Used to choose refresh rate if content detection is enabled.
-    std::unique_ptr<scheduler::LayerHistory> mLayerHistory;
+    std::unique_ptr<LayerHistory> mLayerHistory;
 
     // Whether to use idle timer callbacks that support the kernel timer.
     const bool mSupportKernelTimer;
@@ -236,7 +237,7 @@
         TimerState displayPowerTimer = TimerState::Expired;
 
         std::optional<HwcConfigIndexType> configId;
-        scheduler::LayerHistory::Summary contentRequirements;
+        LayerHistory::Summary contentRequirements;
 
         bool isDisplayPowerStateNormal = true;
     } mFeatures GUARDED_BY(mFeatureStateLock);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c3214f0..83f49dd 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -115,6 +115,7 @@
 #include "Scheduler/DispSyncSource.h"
 #include "Scheduler/EventControlThread.h"
 #include "Scheduler/EventThread.h"
+#include "Scheduler/LayerHistory.h"
 #include "Scheduler/MessageQueue.h"
 #include "Scheduler/PhaseOffsets.h"
 #include "Scheduler/Scheduler.h"
@@ -3401,6 +3402,12 @@
     for (const ComposerState& state : states) {
         clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged,
                                                  listenerCallbacksWithSurfaces);
+        if ((flags & eAnimation) && state.state.surface) {
+            if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) {
+                mScheduler->recordLayerHistory(layer.get(), desiredPresentTime,
+                                               LayerHistory::LayerUpdateType::AnimationTX);
+            }
+        }
     }
 
     for (const auto& listenerCallback : listenerCallbacksWithSurfaces) {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 94ebe89..fe2af80 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -22,6 +22,7 @@
         "Credentials_test.cpp",
         "DereferenceSurfaceControl_test.cpp",
         "DisplayConfigs_test.cpp",
+        "EffectLayer_test.cpp",
         "InvalidHandles_test.cpp",
         "LayerCallback_test.cpp",
         "LayerRenderTypeTransaction_test.cpp",
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
new file mode 100644
index 0000000..3dca391
--- /dev/null
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class EffectLayerTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
+        mParentLayer = createColorLayer("Parent layer", Color::RED);
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
+            t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+            t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+        });
+    }
+
+    virtual void TearDown() {
+        LayerTransactionTest::TearDown();
+        mParentLayer = 0;
+    }
+
+    sp<SurfaceControl> mParentLayer;
+};
+
+TEST_F(EffectLayerTest, DefaultEffectLayerHasSolidBlackFill) {
+    sp<SurfaceControl> effectLayer =
+            mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect,
+                                   mParentLayer.get());
+
+    EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+    asTransaction([&](Transaction& t) {
+        t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+        t.show(effectLayer);
+    });
+
+    {
+        SCOPED_TRACE("Default effect Layer has solid black fill");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 400, 400), Color::BLACK);
+    }
+}
+
+TEST_F(EffectLayerTest, EffectLayerWithNoFill) {
+    sp<SurfaceControl> effectLayer =
+            mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceEffect |
+                                           ISurfaceComposerClient::eNoColorFill,
+                                   mParentLayer.get());
+
+    EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+    asTransaction([&](Transaction& t) {
+        t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+        t.show(effectLayer);
+    });
+
+    {
+        SCOPED_TRACE("Effect layer with nofill option is transparent");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 400, 400), Color::RED);
+    }
+}
+
+TEST_F(EffectLayerTest, EffectLayerCanSetColor) {
+    sp<SurfaceControl> effectLayer =
+            mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceEffect |
+                                           ISurfaceComposerClient::eNoColorFill,
+                                   mParentLayer.get());
+
+    EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+    asTransaction([&](Transaction& t) {
+        t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+        t.setColor(effectLayer,
+                   half3{Color::GREEN.r / 255.0f, Color::GREEN.g / 255.0f,
+                         Color::GREEN.b / 255.0f});
+        t.show(effectLayer);
+    });
+
+    {
+        SCOPED_TRACE("Effect Layer can set color");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 400, 400), Color::GREEN);
+    }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 71d17a9..cae317b 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -96,14 +96,14 @@
 
     // no layers are returned if active layers have insufficient history.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
-        history().record(layer.get(), 0, mTime);
+        history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
         ASSERT_TRUE(history().summarize(mTime).empty());
         EXPECT_EQ(1, activeLayerCount());
     }
 
     // High FPS is returned once enough history has been recorded.
     for (int i = 0; i < 10; i++) {
-        history().record(layer.get(), 0, mTime);
+        history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
         ASSERT_EQ(1, history().summarize(mTime).size());
         EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime)[0].desiredRefreshRate);
         EXPECT_EQ(1, activeLayerCount());
@@ -121,7 +121,7 @@
 
     nsecs_t time = mTime;
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += LO_FPS_PERIOD;
     }
 
@@ -155,7 +155,7 @@
 
     // layer1 is active but infrequent.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer1.get(), time, time);
+        history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
     }
 
@@ -166,12 +166,12 @@
 
     // layer2 is frequent and has high refresh rate.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer2.get(), time, time);
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
     // layer1 is still active but infrequent.
-    history().record(layer1.get(), time, time);
+    history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
 
     ASSERT_EQ(2, history().summarize(time).size());
     EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
@@ -182,7 +182,7 @@
     // layer1 is no longer active.
     // layer2 is frequent and has low refresh rate.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer2.get(), time, time);
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += LO_FPS_PERIOD;
     }
 
@@ -196,10 +196,10 @@
     constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
         if (i % RATIO == 0) {
-            history().record(layer2.get(), time, time);
+            history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         }
 
-        history().record(layer3.get(), time, time);
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
@@ -209,7 +209,7 @@
     EXPECT_EQ(2, frequentLayerCount(time));
 
     // layer3 becomes recently active.
-    history().record(layer3.get(), time, time);
+    history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
     ASSERT_EQ(2, history().summarize(time).size());
     EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
     EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
@@ -228,7 +228,7 @@
     // layer2 still has low refresh rate.
     // layer3 becomes inactive.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer2.get(), time, time);
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += LO_FPS_PERIOD;
     }
 
@@ -246,7 +246,7 @@
 
     // layer3 becomes active and has high refresh rate.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer3.get(), time, time);
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index dc705ed..f376b4a 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "LayerHistoryTestV2"
 
+#include <Layer.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <log/log.h>
@@ -60,6 +61,13 @@
                              [now](const auto& pair) { return pair.second->isFrequent(now); });
     }
 
+    auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+        const auto& infos = history().mLayerInfos;
+        return std::count_if(infos.begin(),
+                             infos.begin() + static_cast<long>(history().mActiveLayersEnd),
+                             [now](const auto& pair) { return pair.second->isAnimating(now); });
+    }
+
     void setLayerInfoVote(Layer* layer,
                           LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
         for (auto& [weak, info] : history().mLayerInfos) {
@@ -109,7 +117,7 @@
 
     // Max returned if active layers have insufficient history.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
-        history().record(layer.get(), 0, time);
+        history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
         ASSERT_EQ(1, history().summarize(time).size());
         EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
         EXPECT_EQ(1, activeLayerCount());
@@ -117,7 +125,7 @@
 
     // Max is returned since we have enough history but there is no timestamp votes.
     for (int i = 0; i < 10; i++) {
-        history().record(layer.get(), 0, time);
+        history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
         ASSERT_EQ(1, history().summarize(time).size());
         EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
         EXPECT_EQ(1, activeLayerCount());
@@ -134,7 +142,7 @@
 
     nsecs_t time = systemTime();
 
-    history().record(layer.get(), 0, time);
+    history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
     auto summary = history().summarize(time);
     ASSERT_EQ(1, history().summarize(time).size());
     // Layer is still considered inactive so we expect to get Min
@@ -158,7 +166,7 @@
 
     nsecs_t time = systemTime();
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += LO_FPS_PERIOD;
     }
 
@@ -181,7 +189,7 @@
 
     nsecs_t time = systemTime();
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
@@ -208,7 +216,7 @@
 
     nsecs_t time = systemTime();
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
@@ -236,7 +244,7 @@
 
     nsecs_t time = systemTime();
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += LO_FPS_PERIOD;
     }
 
@@ -264,7 +272,7 @@
 
     nsecs_t time = systemTime();
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
@@ -296,7 +304,7 @@
 
     nsecs_t time = systemTime();
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
@@ -340,7 +348,7 @@
 
     // layer1 is active but infrequent.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer1.get(), time, time);
+        history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
     }
 
@@ -351,12 +359,12 @@
 
     // layer2 is frequent and has high refresh rate.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer2.get(), time, time);
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
     // layer1 is still active but infrequent.
-    history().record(layer1.get(), time, time);
+    history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
 
     ASSERT_EQ(2, history().summarize(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
@@ -368,7 +376,7 @@
     // layer1 is no longer active.
     // layer2 is frequent and has low refresh rate.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer2.get(), time, time);
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += LO_FPS_PERIOD;
     }
 
@@ -383,10 +391,10 @@
     constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
         if (i % RATIO == 0) {
-            history().record(layer2.get(), time, time);
+            history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         }
 
-        history().record(layer3.get(), time, time);
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
@@ -398,7 +406,7 @@
     EXPECT_EQ(2, frequentLayerCount(time));
 
     // layer3 becomes recently active.
-    history().record(layer3.get(), time, time);
+    history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
     ASSERT_EQ(2, history().summarize(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
     EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
@@ -422,7 +430,7 @@
     // layer2 still has low refresh rate.
     // layer3 becomes inactive.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer2.get(), time, time);
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += LO_FPS_PERIOD;
     }
 
@@ -441,7 +449,7 @@
 
     // layer3 becomes active and has high refresh rate.
     for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
-        history().record(layer3.get(), time, time);
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
     }
 
@@ -470,7 +478,7 @@
 
     // the very first updates makes the layer frequent
     for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
 
         EXPECT_EQ(1, layerCount());
@@ -481,7 +489,7 @@
     }
 
     // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
-    history().record(layer.get(), time, time);
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
     time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
 
     EXPECT_EQ(1, layerCount());
@@ -495,7 +503,7 @@
 
     // Now event if we post a quick few frame we should stay infrequent
     for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
-        history().record(layer.get(), time, time);
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
         time += HI_FPS_PERIOD;
 
         EXPECT_EQ(1, layerCount());
@@ -506,7 +514,7 @@
     }
 
     // More quick frames will get us to frequent again
-    history().record(layer.get(), time, time);
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
     time += HI_FPS_PERIOD;
 
     EXPECT_EQ(1, layerCount());
@@ -533,8 +541,9 @@
     nsecs_t time = systemTime();
 
     // Post a buffer to the layers to make them active
-    history().record(explicitVisiblelayer.get(), time, time);
-    history().record(explicitInvisiblelayer.get(), time, time);
+    history().record(explicitVisiblelayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    history().record(explicitInvisiblelayer.get(), time, time,
+                     LayerHistory::LayerUpdateType::Buffer);
 
     EXPECT_EQ(2, layerCount());
     ASSERT_EQ(1, history().summarize(time).size());
@@ -545,6 +554,52 @@
     EXPECT_EQ(2, frequentLayerCount(time));
 }
 
+TEST_F(LayerHistoryTestV2, infrequentAnimatingLayer) {
+    auto layer = createLayer();
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // layer is active but infrequent.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // another update with the same cadence keep in infrequent
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // an update as animation will immediately vote for Max
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX);
+    time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(1, animatingLayerCount(time));
+}
+
 class LayerHistoryTestV2Parameterized
       : public LayerHistoryTestV2,
         public testing::WithParamInterface<std::chrono::nanoseconds> {};
@@ -565,8 +620,10 @@
     const nsecs_t startTime = systemTime();
 
     const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns;
-    history().record(heuristicLayer.get(), startTime, startTime);
-    history().record(infrequentLayer.get(), startTime, startTime);
+    history().record(heuristicLayer.get(), startTime, startTime,
+                     LayerHistory::LayerUpdateType::Buffer);
+    history().record(infrequentLayer.get(), startTime, startTime,
+                     LayerHistory::LayerUpdateType::Buffer);
 
     nsecs_t time = startTime;
     nsecs_t lastInfrequentUpdate = startTime;
@@ -574,13 +631,14 @@
     int infrequentLayerUpdates = 0;
     while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) {
         time += heuristicUpdateDelta.count();
-        history().record(heuristicLayer.get(), time, time);
+        history().record(heuristicLayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
 
         if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) {
             ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates,
                   totalInfrequentLayerUpdates);
             lastInfrequentUpdate = time;
-            history().record(infrequentLayer.get(), time, time);
+            history().record(infrequentLayer.get(), time, time,
+                             LayerHistory::LayerUpdateType::Buffer);
             infrequentLayerUpdates++;
         }