Merge "Return a copy of InputDeviceLightInfo instead of pointer" into sc-dev
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index ec231b2..fb84f04 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -156,6 +156,10 @@
     ],
     test_suites: ["general-tests"],
     require_root: true,
+    // Prevent the unit test target from running on sc-dev as it's not ready.
+    test_options: {
+        unit_test: false,
+    },
 }
 
 cc_benchmark {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 4e2f879..2c18a60 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -135,6 +135,8 @@
 
     bool hasHdrLayers() const;
 
+    bool hasProtectedLayers() const;
+
 private:
     CachedSet() = default;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 13b8781..a20d7b3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -249,6 +249,10 @@
                 transfer == ui::Dataspace::TRANSFER_HLG);
     }
 
+    bool isProtected() const {
+        return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
+    }
+
     void dump(std::string& result) const;
     std::optional<std::string> compare(const LayerState& other) const;
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 9a294c7..dcfb05d 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -350,6 +350,11 @@
                        [](const Layer& layer) { return layer.getState()->isHdr(); });
 }
 
+bool CachedSet::hasProtectedLayers() const {
+    return std::any_of(mLayers.cbegin(), mLayers.cend(),
+                       [](const Layer& layer) { return layer.getState()->isProtected(); });
+}
+
 void CachedSet::dump(std::string& result) const {
     const auto now = std::chrono::steady_clock::now();
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 550fdeb..233b5f2 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -373,7 +373,7 @@
         const bool layerIsInactive = now - currentSet->getLastUpdate() > kActiveLayerTimeout;
         const bool layerHasBlur = currentSet->hasBlurBehind();
         if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
-            !currentSet->hasHdrLayers()) {
+            !currentSet->hasHdrLayers() && !currentSet->hasProtectedLayers()) {
             if (isPartOfRun) {
                 builder.append(currentSet->getLayerCount());
             } else {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2b4f9ef..a4b6fef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2894,6 +2894,7 @@
     // Commit layer transactions. This needs to happen after display transactions are
     // committed because some geometry logic relies on display orientation.
     if ((transactionFlags & eTraversalNeeded) || mForceTraversal || displayTransactionNeeded) {
+        mForceTraversal = false;
         mCurrentState.traverse([&](Layer* layer) {
             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
             if (!trFlags && !displayTransactionNeeded) return;
@@ -4474,6 +4475,11 @@
     }
     const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
     if (currentMode == hal::PowerMode::OFF) {
+        // Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315.
+        // We can merge the syscall later.
+        if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
+            ALOGW("Couldn't set uclamp.min on display on: %s\n", strerror(errno));
+        }
         if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
             ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
         }
@@ -4492,6 +4498,9 @@
         if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
             ALOGW("Couldn't set SCHED_OTHER on display off: %s\n", strerror(errno));
         }
+        if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
+            ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
+        }
         if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->disableHardwareVsync(true);
             mScheduler->onScreenReleased(mAppConnectionHandle);
@@ -5841,6 +5850,44 @@
     if (sched_setscheduler(0, sched_policy, &param) != 0) {
         return -errno;
     }
+
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setSchedAttr(bool enabled) {
+    static const unsigned int kUclampMin =
+            base::GetUintProperty<unsigned int>("ro.surface_flinger.uclamp.min", 0U);
+
+    if (!kUclampMin) {
+        // uclamp.min set to 0 (default), skip setting
+        return NO_ERROR;
+    }
+
+    // Currently, there is no wrapper in bionic: b/183240349.
+    struct sched_attr {
+        uint32_t size;
+        uint32_t sched_policy;
+        uint64_t sched_flags;
+        int32_t sched_nice;
+        uint32_t sched_priority;
+        uint64_t sched_runtime;
+        uint64_t sched_deadline;
+        uint64_t sched_period;
+        uint32_t sched_util_min;
+        uint32_t sched_util_max;
+    };
+
+    sched_attr attr = {};
+    attr.size = sizeof(attr);
+
+    attr.sched_flags = (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP);
+    attr.sched_util_min = enabled ? kUclampMin : 0;
+    attr.sched_util_max = 1024;
+
+    if (syscall(__NR_sched_setattr, 0, &attr, 0)) {
+        return -errno;
+    }
+
     return NO_ERROR;
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index be3417b..519a5ab 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -186,6 +186,9 @@
     // set main thread scheduling policy
     static status_t setSchedFifo(bool enabled) ANDROID_API;
 
+    // set main thread scheduling attributes
+    static status_t setSchedAttr(bool enabled);
+
     static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; }
 
     // This is the phase offset in nanoseconds of the software vsync event
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 9686523..673239d 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -89,6 +89,12 @@
     // binder threads to 4.
     ProcessState::self()->setThreadPoolMaxThreadCount(4);
 
+    // Set uclamp.min setting on all threads, maybe an overkill but we want
+    // to cover important threads like RenderEngine.
+    if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
+        ALOGW("Couldn't set uclamp.min: %s\n", strerror(errno));
+    }
+
     // The binder threadpool we start will inherit sched policy and priority
     // of (this) creating thread. We want the binder thread pool to have
     // SCHED_FIFO policy and priority 1 (lowest RT priority)