SurfaceFlinger: clear LayerHistory on first touch

 - Restructure the code in RefreshRateConfigs to be able to clear
   LayerHistory frames on the first touch event. Without this change we
   clear the history on every frame as long as the touch timer hasn't
   expired.
 - Add log prints for debugging

Test: Play 24fps video in YouTube PIP mode and rotate the device - no jank
Test: Chrome playing video - no refresh rate switching
Test: Hide/Show keyboard when inputting text
Test: Running Hay Day and observing refresh rate
Bug: 157096772
Change-Id: I7cabecd6ea27ec335e773aa22bb111fa8ec89195
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index 359fe1b..67edef4 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -62,13 +62,17 @@
     const auto layer = weak.promote();
     if (!layer) return;
 
-    const auto& name = layer->getName();
-    const auto noVoteTag = "LFPS NoVote " + name;
-    const auto heuristicVoteTag = "LFPS Heuristic " + name;
-    const auto explicitDefaultVoteTag = "LFPS ExplicitDefault" + name;
-    const auto explicitExactOrMultipleVoteTag = "LFPS ExplicitExactOrMultiple" + name;
-    const auto minVoteTag = "LFPS Min " + name;
-    const auto maxVoteTag = "LFPS Max " + name;
+    const auto makeTag = [layer](LayerHistory::LayerVoteType vote) {
+        return "LFPS " + RefreshRateConfigs::layerVoteTypeString(vote) + " " + layer->getName();
+    };
+
+    const auto noVoteTag = makeTag(LayerHistory::LayerVoteType::NoVote);
+    const auto heuristicVoteTag = makeTag(LayerHistory::LayerVoteType::Heuristic);
+    const auto explicitDefaultVoteTag = makeTag(LayerHistory::LayerVoteType::ExplicitDefault);
+    const auto explicitExactOrMultipleVoteTag =
+            makeTag(LayerHistory::LayerVoteType::ExplicitExactOrMultiple);
+    const auto minVoteTag = makeTag(LayerHistory::LayerVoteType::Min);
+    const auto maxVoteTag = makeTag(LayerHistory::LayerVoteType::Max);
 
     ATRACE_INT(noVoteTag.c_str(), type == LayerHistory::LayerVoteType::NoVote ? 1 : 0);
     ATRACE_INT(heuristicVoteTag.c_str(), type == LayerHistory::LayerVoteType::Heuristic ? fps : 0);
@@ -79,7 +83,7 @@
     ATRACE_INT(minVoteTag.c_str(), type == LayerHistory::LayerVoteType::Min ? 1 : 0);
     ATRACE_INT(maxVoteTag.c_str(), type == LayerHistory::LayerVoteType::Max ? 1 : 0);
 
-    ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
+    ALOGD("%s: %s @ %d Hz", __FUNCTION__, layer->getName().c_str(), fps);
 }
 } // namespace
 
@@ -90,7 +94,7 @@
 void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
                                    LayerVoteType type) {
     const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate);
-    auto info = std::make_unique<LayerInfoV2>(highRefreshRatePeriod, type);
+    auto info = std::make_unique<LayerInfoV2>(layer->getName(), highRefreshRatePeriod, type);
     std::lock_guard lock(mLock);
     mLayerInfos.emplace_back(layer, std::move(info));
 }
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index 8a6d52a..276afd8 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -27,8 +27,10 @@
 
 namespace android::scheduler {
 
-LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote)
-      : mHighRefreshRatePeriod(highRefreshRatePeriod),
+LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
+                         LayerHistory::LayerVoteType defaultVote)
+      : mName(name),
+        mHighRefreshRatePeriod(highRefreshRatePeriod),
         mDefaultVote(defaultVote),
         mLayerVote({defaultVote, 0.0f}) {}
 
@@ -191,18 +193,22 @@
 
 std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
     if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
+        ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type));
         return {mLayerVote.type, mLayerVote.fps};
     }
 
     if (!isFrequent(now)) {
+        ALOGV("%s is infrequent", mName.c_str());
         return {LayerHistory::LayerVoteType::Min, 0};
     }
 
     auto refreshRate = calculateRefreshRateIfPossible();
     if (refreshRate.has_value()) {
+        ALOGV("%s calculated refresh rate: %.2f", mName.c_str(), refreshRate.value());
         return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
     }
 
+    ALOGV("%s Max (can't resolve refresh rate)", mName.c_str());
     return {LayerHistory::LayerVoteType::Max, 0};
 }
 
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 47945d1..f2d29c5 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -54,7 +54,8 @@
     friend class LayerHistoryTestV2;
 
 public:
-    LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote);
+    LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
+                LayerHistory::LayerVoteType defaultVote);
 
     LayerInfoV2(const LayerInfo&) = delete;
     LayerInfoV2& operator=(const LayerInfoV2&) = delete;
@@ -106,6 +107,8 @@
     bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const;
     bool isFrameTimeValid(const FrameTimeData&) const;
 
+    const std::string mName;
+
     // Used for sanitizing the heuristic data
     const nsecs_t mHighRefreshRatePeriod;
     LayerHistory::LayerVoteType mDefaultVote;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 651283f..3c8bd68 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -31,6 +31,23 @@
 using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
 using RefreshRate = RefreshRateConfigs::RefreshRate;
 
+std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
+    switch (vote) {
+        case LayerVoteType::NoVote:
+            return "NoVote";
+        case LayerVoteType::Min:
+            return "Min";
+        case LayerVoteType::Max:
+            return "Max";
+        case LayerVoteType::Heuristic:
+            return "Heuristic";
+        case LayerVoteType::ExplicitDefault:
+            return "ExplicitDefault";
+        case LayerVoteType::ExplicitExactOrMultiple:
+            return "ExplicitExactOrMultiple";
+    }
+}
+
 const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
         const std::vector<LayerRequirement>& layers) const {
     std::lock_guard lock(mLock);
@@ -103,7 +120,7 @@
     ATRACE_CALL();
     ALOGV("getRefreshRateForContent %zu layers", layers.size());
 
-    *touchConsidered = false;
+    if (touchConsidered) *touchConsidered = false;
     std::lock_guard lock(mLock);
 
     int noVoteLayers = 0;
@@ -134,7 +151,8 @@
     // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
     // selected a refresh rate to see if we should apply touch boost.
     if (touchActive && !hasExplicitVoteLayers) {
-        *touchConsidered = true;
+        ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
+        if (touchConsidered) *touchConsidered = true;
         return getMaxRefreshRateByPolicyLocked();
     }
 
@@ -145,6 +163,7 @@
     const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
 
     if (!touchActive && idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
+        ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
         return getMinRefreshRateByPolicyLocked();
     }
 
@@ -154,6 +173,7 @@
 
     // Only if all layers want Min we should return Min
     if (noVoteLayers + minVoteLayers == layers.size()) {
+        ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
         return getMinRefreshRateByPolicyLocked();
     }
 
@@ -166,7 +186,8 @@
     }
 
     for (const auto& layer : layers) {
-        ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote);
+        ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
+              layerVoteTypeString(layer.vote).c_str(), layer.weight);
         if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
             continue;
         }
@@ -251,9 +272,9 @@
 
                     return 1.0f / iter;
                 }();
-                ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f",
-                      layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(),
-                      layerScore);
+                ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
+                      layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod,
+                      scores[i].first->name.c_str(), layerScore);
                 scores[i].second += weight * layerScore;
                 continue;
             }
@@ -272,6 +293,8 @@
         // range instead of picking a random score from the app range.
         if (std::all_of(scores.begin(), scores.end(),
                         [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
+            ALOGV("layers not scored - choose %s",
+                  getMaxRefreshRateByPolicyLocked().getName().c_str());
             return getMaxRefreshRateByPolicyLocked();
         } else {
             return *bestRefreshRate;
@@ -286,7 +309,8 @@
 
     if (touchActive && explicitDefaultVoteLayers == 0 &&
         bestRefreshRate->fps < touchRefreshRate.fps) {
-        *touchConsidered = true;
+        if (touchConsidered) *touchConsidered = true;
+        ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
         return touchRefreshRate;
     }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 2657dee..ff1eabd 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -255,6 +255,9 @@
     // Stores the current configId the device operates at
     void setCurrentConfigId(HwcConfigIndexType configId) EXCLUDES(mLock);
 
+    // Returns a string that represents the layer vote type
+    static std::string layerVoteTypeString(LayerVoteType vote);
+
     RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
                        HwcConfigIndexType currentConfigId);
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index dcce08d..7c2af23 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -527,7 +527,9 @@
 
 void Scheduler::touchTimerCallback(TimerState state) {
     const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
-    handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
+    if (handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */)) {
+        mLayerHistory->clear();
+    }
     ATRACE_INT("TouchState", static_cast<int>(touch));
 }
 
@@ -550,18 +552,19 @@
 }
 
 template <class T>
-void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
+bool Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
     ConfigEvent event = ConfigEvent::None;
     HwcConfigIndexType newConfigId;
+    bool touchConsidered = false;
     {
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
         if (*currentState == newState) {
-            return;
+            return touchConsidered;
         }
         *currentState = newState;
-        newConfigId = calculateRefreshRateConfigIndexType();
+        newConfigId = calculateRefreshRateConfigIndexType(&touchConsidered);
         if (mFeatures.configId == newConfigId) {
-            return;
+            return touchConsidered;
         }
         mFeatures.configId = newConfigId;
         if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) {
@@ -570,10 +573,12 @@
     }
     const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
     mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
+    return touchConsidered;
 }
 
-HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
+HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType(bool* touchConsidered) {
     ATRACE_CALL();
+    if (touchConsidered) *touchConsidered = false;
 
     // If Display Power is not in normal operation we want to be in performance mode. When coming
     // back to normal mode, a grace period is given with DisplayPowerTimer.
@@ -608,18 +613,9 @@
                 .getConfigId();
     }
 
-    bool touchConsidered;
-    const auto& ret = mRefreshRateConfigs
-                              .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle,
-                                                  &touchConsidered)
-                              .getConfigId();
-    if (touchConsidered) {
-        // Clear layer history if refresh rate was selected based on touch to allow
-        // the hueristic to pick up with the new rate.
-        mLayerHistory->clear();
-    }
-
-    return ret;
+    return mRefreshRateConfigs
+            .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle, touchConsidered)
+            .getConfigId();
 }
 
 std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9cea4cc..066e9ca 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -178,14 +178,15 @@
 
     // handles various timer features to change the refresh rate.
     template <class T>
-    void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection);
+    bool handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection);
 
     void setVsyncPeriod(nsecs_t period);
 
     // This function checks whether individual features that are affecting the refresh rate
     // selection were initialized, prioritizes them, and calculates the HwcConfigIndexType
     // for the suggested refresh rate.
-    HwcConfigIndexType calculateRefreshRateConfigIndexType() REQUIRES(mFeatureStateLock);
+    HwcConfigIndexType calculateRefreshRateConfigIndexType(bool* touchConsidered = nullptr)
+            REQUIRES(mFeatureStateLock);
 
     // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
     struct Connection {