Adding support for the setFrameRate() API to SurfaceFlinger path

- When choosing the max refresh rate in Layer History, check if
the layer has the bit set, if so use it.
- Disable touch boost/choosing config with max refresh rate,
when the layer has framerate set.

Test: Run unit test. Observe logs.
Test: Extend unit test to 10sec. Tap on screen while it's running.
      Observe logs. Tap, should not reset the max refresh rate.
Change-Id: Ibe2689964c9f92788ace1b08c3521f156cb47524
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 8219a7d..abf0cd6 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -43,6 +43,9 @@
 namespace {
 
 bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
+    if (layer.getFrameRate() > .0f) {
+        return layer.isVisible();
+    }
     return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
 }
 
@@ -117,11 +120,32 @@
                     // Layers should be organized by priority
                     ALOGD("Layer has priority: %d", priority);
                 }
+            }
+        }
+    }
+
+    for (const auto& [weakLayer, info] : activeLayers()) {
+        const bool recent = info->isRecentlyActive(now);
+        auto layer = weakLayer.promote();
+        // Only use the layer if the reference still exists.
+        if (layer || CC_UNLIKELY(mTraceEnabled)) {
+            float refreshRate = 0.f;
+            // Default content refresh rate is only used when dealing with recent layers.
+            if (recent) {
+                refreshRate = info->getRefreshRate(now);
+            }
+            // Check if frame rate was set on layer.
+            float frameRate = layer->getFrameRate();
+            if (frameRate > 0.f) {
+                // Override content detection refresh rate, if it was set.
+                refreshRate = frameRate;
+            }
+            if (refreshRate > maxRefreshRate) {
                 maxRefreshRate = refreshRate;
             }
 
             if (CC_UNLIKELY(mTraceEnabled)) {
-                trace(activeLayer, std::round(refreshRate));
+                trace(weakLayer, std::round(refreshRate));
             }
         }
     }
@@ -175,6 +199,22 @@
     mActiveLayersEnd = 0;
 }
 
+bool LayerHistory::hasClientSpecifiedFrameRate() {
+    std::lock_guard lock(mLock);
+    for (const auto& [weakLayer, info] : activeLayers()) {
+        auto layer = weakLayer.promote();
+        if (layer) {
+            float frameRate = layer->getFrameRate();
+            // Found a layer that has a frame rate set on it.
+            if (fabs(frameRate) > 0.f) {
+                return true;
+            }
+        }
+    }
+    // Did not find any layers that have frame rate.
+    return false;
+}
+
 } // namespace android::scheduler::impl
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 188fa64..f217134 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -53,6 +53,9 @@
     virtual Summary summarize(nsecs_t now) = 0;
 
     virtual void clear() = 0;
+
+    // Checks whether any of the active layers have a desired frame rate bit set on them.
+    virtual bool hasClientSpecifiedFrameRate() = 0;
 };
 
 namespace impl {
@@ -75,6 +78,10 @@
 
     void clear() override;
 
+    // Traverses all active layers and checks whether any of them have a desired frame
+    // rate bit set on them.
+    bool hasClientSpecifiedFrameRate() override;
+
 private:
     friend class android::scheduler::LayerHistoryTest;
     friend TestableScheduler;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c96eba4..0b645c4 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -422,18 +422,20 @@
 }
 
 void Scheduler::notifyTouchEvent() {
-    if (mTouchTimer) {
-        mTouchTimer->reset();
-    }
-
-    if (mSupportKernelTimer && mIdleTimer) {
-        mIdleTimer->reset();
-    }
-
     // Touch event will boost the refresh rate to performance.
-    // Clear Layer History to get fresh FPS detection
-    if (mLayerHistory) {
+    // Clear Layer History to get fresh FPS detection.
+    // NOTE: Instead of checking all the layers, we should be checking the layer
+    // that is currently on top. b/142507166 will give us this capability.
+    if (mLayerHistory && !mLayerHistory->hasClientSpecifiedFrameRate()) {
         mLayerHistory->clear();
+
+        if (mTouchTimer) {
+            mTouchTimer->reset();
+        }
+
+        if (mSupportKernelTimer && mIdleTimer) {
+            mIdleTimer->reset();
+        }
     }
 }
 
@@ -533,25 +535,31 @@
         return mRefreshRateConfigs.getCurrentRefreshRate().configId;
     }
 
-    // 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
-    if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
-        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
-    }
+    // If the layer history doesn't have the frame rate specified, use the old path. NOTE:
+    // if we remove the kernel idle timer, and use our internal idle timer, this code will have to
+    // be refactored.
+    if (!mLayerHistory->hasClientSpecifiedFrameRate()) {
+        // 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
+        if (!mFeatures.isDisplayPowerStateNormal ||
+            mFeatures.displayPowerTimer == TimerState::Reset) {
+            return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        }
 
-    // As long as touch is active we want to be in performance mode
-    if (mFeatures.touch == TouchState::Active) {
-        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
-    }
+        // As long as touch is active we want to be in performance mode
+        if (mFeatures.touch == TouchState::Active) {
+            return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        }
 
-    // If timer has expired as it means there is no new content on the screen
-    if (mFeatures.idleTimer == TimerState::Expired) {
-        return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
-    }
+        // If timer has expired as it means there is no new content on the screen
+        if (mFeatures.idleTimer == TimerState::Expired) {
+            return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
+        }
 
-    // If content detection is off we choose performance as we don't know the content fps
-    if (mFeatures.contentDetection == ContentDetectionState::Off) {
-        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        // If content detection is off we choose performance as we don't know the content fps
+        if (mFeatures.contentDetection == ContentDetectionState::Off) {
+            return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        }
     }
 
     // Content detection is on, find the appropriate refresh rate with minimal error