SF: Optimize layer history in scheduler

Register layers with LayerHistory by storing a weak pointer rather than
allocating a LayerHandle. Query layer visibility when needed instead of
synchronizing it to LayerInfo whenever Layer::isVisible is called. Store
active/inactive layers in contiguous memory instead of two hash maps for
cache efficiency, and minimal allocation and run time of operations like
clearing history. Remove redundant ref-counting, locking, and frequency-
period conversion in LayerInfo. Avoid sleeping in unit tests.

This is also prework for per-display layer history.

Bug: 130554049
Bug: 134772048
Test: go/wm-smoke with debug.sf.layer_history_trace
Test: C2/F2 test cases from spreadsheet
Test: LayerHistoryTest with new test cases
Change-Id: Ibfcfe46cd76ebd93b916d4a0c737a19e837d4ff1
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 17afdda..b86709f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -16,27 +16,37 @@
 
 #pragma once
 
-#include <cinttypes>
-#include <cstdint>
-#include <deque>
-#include <mutex>
-#include <numeric>
-#include <string>
-
-#include <log/log.h>
-
-#include <utils/Mutex.h>
 #include <utils/Timers.h>
 
+#include <chrono>
+#include <deque>
+
 #include "SchedulerUtils.h"
 
 namespace android {
+
+class Layer;
+
 namespace scheduler {
 
-/*
- * This class represents information about individial layers.
- */
+using namespace std::chrono_literals;
+
+// Maximum period between presents for a layer to be considered active.
+constexpr std::chrono::nanoseconds MAX_ACTIVE_LAYER_PERIOD_NS = 1200ms;
+
+// Earliest present time for a layer to be considered active.
+constexpr nsecs_t getActiveLayerThreshold(nsecs_t now) {
+    return now - MAX_ACTIVE_LAYER_PERIOD_NS.count();
+}
+
+// Stores history of present times and refresh rates for a layer.
 class LayerInfo {
+    // 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.
+    static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
+    static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms;
+
     /**
      * Struct that keeps the information about the refresh rate for last
      * HISTORY_SIZE frames. This is used to better determine the refresh rate
@@ -44,9 +54,9 @@
      */
     class RefreshRateHistory {
     public:
-        explicit RefreshRateHistory(nsecs_t minRefreshDuration)
-              : mMinRefreshDuration(minRefreshDuration) {}
-        void insertRefreshRate(int refreshRate) {
+        explicit RefreshRateHistory(float highRefreshRate) : mHighRefreshRate(highRefreshRate) {}
+
+        void insertRefreshRate(float refreshRate) {
             mElements.push_back(refreshRate);
             if (mElements.size() > HISTORY_SIZE) {
                 mElements.pop_front();
@@ -54,19 +64,16 @@
         }
 
         float getRefreshRateAvg() const {
-            if (mElements.empty()) {
-                return 1e9f / mMinRefreshDuration;
-            }
-
-            return scheduler::calculate_mean(mElements);
+            return mElements.empty() ? mHighRefreshRate : calculate_mean(mElements);
         }
 
         void clearHistory() { mElements.clear(); }
 
     private:
-        std::deque<nsecs_t> mElements;
+        const float mHighRefreshRate;
+
         static constexpr size_t HISTORY_SIZE = 30;
-        const nsecs_t mMinRefreshDuration;
+        std::deque<float> mElements;
     };
 
     /**
@@ -76,6 +83,8 @@
      */
     class PresentTimeHistory {
     public:
+        static constexpr size_t HISTORY_SIZE = 90;
+
         void insertPresentTime(nsecs_t presentTime) {
             mElements.push_back(presentTime);
             if (mElements.size() > HISTORY_SIZE) {
@@ -83,60 +92,45 @@
             }
         }
 
-        // Checks whether the present time that was inserted HISTORY_SIZE ago is within a
-        // certain threshold: TIME_EPSILON_NS.
-        bool isRelevant() const {
+        // Returns whether the earliest present time is within the active threshold.
+        bool isRecentlyActive(nsecs_t now) const {
             if (mElements.size() < 2) {
                 return false;
             }
 
             // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
-            if (mElements.size() != HISTORY_SIZE &&
-                mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) {
+            if (mElements.size() < HISTORY_SIZE &&
+                mElements.back() - mElements.front() < HISTORY_TIME.count()) {
                 return false;
             }
 
-            // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds.
-            const int64_t obsoleteEpsilon =
-                    systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
-            if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) {
-                return false;
-            }
-
-            return true;
+            return mElements.back() >= getActiveLayerThreshold(now);
         }
 
-        bool isLowActivityLayer() const {
-            // We want to make sure that we received more than two frames from the layer
-            // in order to check low activity.
-            if (mElements.size() < scheduler::LOW_ACTIVITY_BUFFERS + 1) {
+        bool isFrequent(nsecs_t now) const {
+            // Assume layer is infrequent if too few present times have been recorded.
+            if (mElements.size() < FREQUENT_LAYER_WINDOW_SIZE) {
                 return false;
             }
 
-            const int64_t obsoleteEpsilon =
-                    systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count();
-            // Check the frame before last to determine whether there is low activity.
-            // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending
-            // infrequent updates.
-            if (mElements.at(mElements.size() - (scheduler::LOW_ACTIVITY_BUFFERS + 1)) <
-                obsoleteEpsilon) {
-                return true;
-            }
-
-            return false;
+            // Layer is frequent if the earliest value in the window of most recent present times is
+            // within threshold.
+            const auto it = mElements.end() - FREQUENT_LAYER_WINDOW_SIZE;
+            const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
+            return *it >= threshold;
         }
 
         void clearHistory() { mElements.clear(); }
 
     private:
         std::deque<nsecs_t> mElements;
-        static constexpr size_t HISTORY_SIZE = 90;
         static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
     };
 
+    friend class LayerHistoryTest;
+
 public:
-    LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate);
-    ~LayerInfo();
+    LayerInfo(float lowRefreshRate, float highRefreshRate);
 
     LayerInfo(const LayerInfo&) = delete;
     LayerInfo& operator=(const LayerInfo&) = delete;
@@ -144,71 +138,37 @@
     // Records the last requested oresent 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);
+    void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now);
 
-    void setHDRContent(bool isHdr) {
-        std::lock_guard lock(mLock);
-        mIsHDR = isHdr;
-    }
+    bool isHDR() const { return mIsHDR; }
+    void setIsHDR(bool isHDR) { mIsHDR = isHDR; }
 
-    void setVisibility(bool visible) {
-        std::lock_guard lock(mLock);
-        mIsVisible = visible;
-    }
+    bool isRecentlyActive(nsecs_t now) const { return mPresentTimeHistory.isRecentlyActive(now); }
+    bool isFrequent(nsecs_t now) const { return mPresentTimeHistory.isFrequent(now); }
 
-    // Checks the present time history to see whether the layer is relevant.
-    bool isRecentlyActive() const {
-        std::lock_guard lock(mLock);
-        return mPresentTimeHistory.isRelevant();
-    }
-
-    // Calculate the average refresh rate.
-    float getDesiredRefreshRate() const {
-        std::lock_guard lock(mLock);
-
-        if (mPresentTimeHistory.isLowActivityLayer()) {
-            return 1e9f / mLowActivityRefreshDuration;
-        }
-        return mRefreshRateHistory.getRefreshRateAvg();
-    }
-
-    bool getHDRContent() {
-        std::lock_guard lock(mLock);
-        return mIsHDR;
-    }
-
-    bool isVisible() {
-        std::lock_guard lock(mLock);
-        return mIsVisible;
+    float getRefreshRate(nsecs_t now) const {
+        return isFrequent(now) ? mRefreshRateHistory.getRefreshRateAvg() : mLowRefreshRate;
     }
 
     // Return the last updated time. If the present time is farther in the future than the
     // updated time, the updated time is the present time.
-    nsecs_t getLastUpdatedTime() {
-        std::lock_guard lock(mLock);
-        return mLastUpdatedTime;
-    }
-
-    std::string getName() const { return mName; }
+    nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
 
     void clearHistory() {
-        std::lock_guard lock(mLock);
         mRefreshRateHistory.clearHistory();
         mPresentTimeHistory.clearHistory();
     }
 
 private:
-    const std::string mName;
-    const nsecs_t mMinRefreshDuration;
-    const nsecs_t mLowActivityRefreshDuration;
-    mutable std::mutex mLock;
-    nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
-    nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
-    RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock);
-    PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock);
-    bool mIsHDR GUARDED_BY(mLock) = false;
-    bool mIsVisible GUARDED_BY(mLock) = false;
+    const float mLowRefreshRate;
+    const float mHighRefreshRate;
+
+    nsecs_t mLastUpdatedTime = 0;
+    nsecs_t mLastPresentTime = 0;
+    RefreshRateHistory mRefreshRateHistory{mHighRefreshRate};
+    PresentTimeHistory mPresentTimeHistory;
+    bool mIsHDR = false;
 };
 
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android