Merge "VRR: Allowlist for small area detection" into udc-qpr-dev am: 89270bc758
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/24536647
Change-Id: I1d87f5ae013cbc2752ffed7d235705c1c5d87856
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index cab9009..00495ee 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2750,6 +2750,20 @@
return statusTFromBinderStatus(status);
}
+status_t SurfaceComposerClient::updateSmallAreaDetection(std::vector<int32_t>& uids,
+ std::vector<float>& thresholds) {
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->updateSmallAreaDetection(uids, thresholds);
+ return statusTFromBinderStatus(status);
+}
+
+status_t SurfaceComposerClient::setSmallAreaDetectionThreshold(uid_t uid, float threshold) {
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->setSmallAreaDetectionThreshold(uid,
+ threshold);
+ return statusTFromBinderStatus(status);
+}
+
void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on);
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 7e652ac..516d159 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -481,6 +481,15 @@
*/
void setOverrideFrameRate(int uid, float frameRate);
+ oneway void updateSmallAreaDetection(in int[] uids, in float[] thresholds);
+
+ /**
+ * Set the small area detection threshold for a specified uid by SmallAreaDetectionController.
+ * Passing the threshold and uid to SurfaceFlinger to update the uid-threshold mapping
+ * in the scheduler.
+ */
+ oneway void setSmallAreaDetectionThreshold(int uid, float threshold);
+
/**
* Gets priority of the RenderEngine in SurfaceFlinger.
*/
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index c70197c..67915f9 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -151,6 +151,9 @@
MOCK_METHOD(binder::Status, getDisplayDecorationSupport,
(const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override));
MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override));
+ MOCK_METHOD(binder::Status, updateSmallAreaDetection,
+ (const std::vector<int32_t>&, const std::vector<float>&), (override));
+ MOCK_METHOD(binder::Status, setSmallAreaDetectionThreshold, (int32_t, float), (override));
MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override));
MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override));
MOCK_METHOD(binder::Status, addWindowInfosListener,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index dbcbd3b..7c55100 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -203,6 +203,16 @@
// by GameManager.
static status_t setOverrideFrameRate(uid_t uid, float frameRate);
+ // Update the small area detection whole uid-threshold mappings by same size uid and threshold
+ // vector.
+ // Ref:setSmallAreaDetectionThreshold.
+ static status_t updateSmallAreaDetection(std::vector<int32_t>& uids,
+ std::vector<float>& thresholds);
+
+ // Sets the small area detection threshold to particular apps (uid). Passing value 0 means
+ // to disable small area detection to the app.
+ static status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold);
+
// Switches on/off Auto Low Latency Mode on the connected display. This should only be
// called if the connected display supports Auto Low Latency Mode as reported by
// #getAutoLowLatencyModeSupport
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 113563d..6adcd96 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -993,6 +993,15 @@
return binder::Status::ok();
}
+ binder::Status updateSmallAreaDetection(const std::vector<int32_t>& /*uids*/,
+ const std::vector<float>& /*thresholds*/) {
+ return binder::Status::ok();
+ }
+
+ binder::Status setSmallAreaDetectionThreshold(int32_t /*uid*/, float /*threshold*/) {
+ return binder::Status::ok();
+ }
+
binder::Status getGpuContextPriority(int32_t* /*outPriority*/) override {
return binder::Status::ok();
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5683a92..0e6d8b1 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -185,6 +185,7 @@
"Scheduler/MessageQueue.cpp",
"Scheduler/RefreshRateSelector.cpp",
"Scheduler/Scheduler.cpp",
+ "Scheduler/SmallAreaDetectionAllowMappings.cpp",
"Scheduler/VSyncDispatchTimerQueue.cpp",
"Scheduler/VSyncPredictor.cpp",
"Scheduler/VSyncReactor.cpp",
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 97eda5d..a186ad4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -4363,7 +4363,8 @@
// If the damage region is a small dirty, this could give the hint for the layer history that
// it could suppress the heuristic rate when calculating.
- mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(bounds.getWidth() * bounds.getHeight());
+ mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerUid,
+ bounds.getWidth() * bounds.getHeight());
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index a812ab7..6adffc9 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -320,9 +320,9 @@
return {LayerStatus::NotFound, nullptr};
}
-bool LayerHistory::isSmallDirtyArea(uint32_t dirtyArea) const {
+bool LayerHistory::isSmallDirtyArea(uint32_t dirtyArea, float threshold) const {
const float ratio = (float)dirtyArea / mDisplayArea;
- const bool isSmallDirty = ratio <= kSmallDirtyArea;
+ const bool isSmallDirty = ratio <= threshold;
ATRACE_FORMAT_INSTANT("small dirty=%s, ratio=%.3f", isSmallDirty ? "true" : "false", ratio);
return isSmallDirty;
}
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 0636415..6f07e3b 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -88,14 +88,12 @@
void attachChoreographer(int32_t layerId,
const sp<EventThreadConnection>& choreographerConnection);
- bool isSmallDirtyArea(uint32_t dirtyArea) const;
+ bool isSmallDirtyArea(uint32_t dirtyArea, float threshold) const;
private:
friend class LayerHistoryTest;
friend class TestableScheduler;
- static constexpr float kSmallDirtyArea = 0.07f;
-
using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>;
// keyed by id as returned from Layer::getSequence()
using LayerInfos = std::unordered_map<int32_t, LayerPair>;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 0b6ce80..68927bd 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -1048,4 +1048,20 @@
mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride);
}
+void Scheduler::updateSmallAreaDetection(
+ std::vector<std::pair<uid_t, float>>& uidThresholdMappings) {
+ mSmallAreaDetectionAllowMappings.update(uidThresholdMappings);
+}
+
+void Scheduler::setSmallAreaDetectionThreshold(uid_t uid, float threshold) {
+ mSmallAreaDetectionAllowMappings.setThesholdForUid(uid, threshold);
+}
+
+bool Scheduler::isSmallDirtyArea(uid_t uid, uint32_t dirtyArea) {
+ std::optional<float> oThreshold = mSmallAreaDetectionAllowMappings.getThresholdForUid(uid);
+ if (oThreshold) return mLayerHistory.isSmallDirtyArea(dirtyArea, oThreshold.value());
+
+ return false;
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index d3c8079..20cc77f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -49,6 +49,7 @@
#include "MessageQueue.h"
#include "OneShotTimer.h"
#include "RefreshRateSelector.h"
+#include "SmallAreaDetectionAllowMappings.h"
#include "Utils/Dumper.h"
#include "VsyncModulator.h"
@@ -289,6 +290,13 @@
void setGameModeRefreshRateForUid(FrameRateOverride);
+ void updateSmallAreaDetection(std::vector<std::pair<uid_t, float>>& uidThresholdMappings);
+
+ void setSmallAreaDetectionThreshold(uid_t uid, float threshold);
+
+ // Returns true if the dirty area is less than threshold.
+ bool isSmallDirtyArea(uid_t uid, uint32_t dirtyArea);
+
// Retrieves the overridden refresh rate for a given uid.
std::optional<Fps> getFrameRateOverride(uid_t) const EXCLUDES(mDisplayLock);
@@ -310,11 +318,6 @@
return mFeatures.test(Feature::kSmallDirtyContentDetection);
}
- // Returns true if the dirty area is less than threshold.
- bool isSmallDirtyArea(uint32_t dirtyArea) const {
- return mLayerHistory.isSmallDirtyArea(dirtyArea);
- }
-
private:
friend class TestableScheduler;
@@ -539,6 +542,7 @@
static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
FrameRateOverrideMappings mFrameRateOverrideMappings;
+ SmallAreaDetectionAllowMappings mSmallAreaDetectionAllowMappings;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp
new file mode 100644
index 0000000..95cd5d1
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 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.
+ */
+#include <sys/types.h>
+
+#include "SmallAreaDetectionAllowMappings.h"
+
+namespace android::scheduler {
+void SmallAreaDetectionAllowMappings::update(
+ std::vector<std::pair<uid_t, float>>& uidThresholdMappings) {
+ std::lock_guard lock(mLock);
+ mMap.clear();
+ for (std::pair<uid_t, float> row : uidThresholdMappings) {
+ if (!isValidThreshold(row.second)) continue;
+
+ mMap.emplace(row.first, row.second);
+ }
+}
+
+void SmallAreaDetectionAllowMappings::setThesholdForUid(uid_t uid, float threshold) {
+ if (!isValidThreshold(threshold)) return;
+
+ std::lock_guard lock(mLock);
+ mMap.emplace(uid, threshold);
+}
+
+std::optional<float> SmallAreaDetectionAllowMappings::getThresholdForUid(uid_t uid) {
+ std::lock_guard lock(mLock);
+ const auto iter = mMap.find(uid);
+ if (iter != mMap.end()) {
+ return iter->second;
+ }
+ return std::nullopt;
+}
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h
new file mode 100644
index 0000000..cbab690
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <sys/types.h>
+#include <optional>
+#include <unordered_map>
+#include <vector>
+
+namespace android::scheduler {
+class SmallAreaDetectionAllowMappings {
+ using UidThresholdMap = std::unordered_map<uid_t, float>;
+
+public:
+ void update(std::vector<std::pair<uid_t, float>>& uidThresholdMappings);
+ void setThesholdForUid(uid_t uid, float threshold) EXCLUDES(mLock);
+ std::optional<float> getThresholdForUid(uid_t uid) EXCLUDES(mLock);
+
+private:
+ static bool isValidThreshold(float threshold) { return threshold >= 0.0f && threshold <= 1.0f; }
+ mutable std::mutex mLock;
+ UidThresholdMap mMap GUARDED_BY(mLock);
+};
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 07704fb..9ebd051 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -7841,6 +7841,17 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::updateSmallAreaDetection(
+ std::vector<std::pair<uid_t, float>>& uidThresholdMappings) {
+ mScheduler->updateSmallAreaDetection(uidThresholdMappings);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setSmallAreaDetectionThreshold(uid_t uid, float threshold) {
+ mScheduler->setSmallAreaDetectionThreshold(uid, threshold);
+ return NO_ERROR;
+}
+
void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
bool setByHwc = getHwComposer().hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG);
for (const auto& [id, display] : mPhysicalDisplays) {
@@ -9116,6 +9127,40 @@
return binderStatusFromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector<int32_t>& uids,
+ const std::vector<float>& thresholds) {
+ status_t status;
+ const int c_uid = IPCThreadState::self()->getCallingUid();
+ if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
+ if (uids.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE);
+
+ std::vector<std::pair<uid_t, float>> mappings;
+ const size_t size = uids.size();
+ mappings.reserve(size);
+ for (int i = 0; i < size; i++) {
+ auto row = std::make_pair(static_cast<uid_t>(uids[i]), thresholds[i]);
+ mappings.push_back(row);
+ }
+ status = mFlinger->updateSmallAreaDetection(mappings);
+ } else {
+ ALOGE("updateSmallAreaDetection() permission denied for uid: %d", c_uid);
+ status = PERMISSION_DENIED;
+ }
+ return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setSmallAreaDetectionThreshold(int32_t uid, float threshold) {
+ status_t status;
+ const int c_uid = IPCThreadState::self()->getCallingUid();
+ if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
+ status = mFlinger->setSmallAreaDetectionThreshold(uid, threshold);
+ } else {
+ ALOGE("setSmallAreaDetectionThreshold() permission denied for uid: %d", c_uid);
+ status = PERMISSION_DENIED;
+ }
+ return binderStatusFromStatusT(status);
+}
+
binder::Status SurfaceComposerAIDL::getGpuContextPriority(int32_t* outPriority) {
*outPriority = mFlinger->getGpuContextPriority();
return binder::Status::ok();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f1989db..427e6bb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -614,6 +614,10 @@
status_t setOverrideFrameRate(uid_t uid, float frameRate);
+ status_t updateSmallAreaDetection(std::vector<std::pair<uid_t, float>>& uidThresholdMappings);
+
+ status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold);
+
int getGpuContextPriority();
status_t getMaxAcquiredBufferCount(int* buffers) const;
@@ -1547,6 +1551,9 @@
const sp<IBinder>& displayToken,
std::optional<gui::DisplayDecorationSupport>* outSupport) override;
binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override;
+ binder::Status updateSmallAreaDetection(const std::vector<int32_t>& uids,
+ const std::vector<float>& thresholds) override;
+ binder::Status setSmallAreaDetectionThreshold(int32_t uid, float threshold) override;
binder::Status getGpuContextPriority(int32_t* outPriority) override;
binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override;
binder::Status addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener,
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 86af303..ceb69df 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -100,6 +100,7 @@
"LayerTestUtils.cpp",
"MessageQueueTest.cpp",
"PowerAdvisorTest.cpp",
+ "SmallAreaDetectionAllowMappingsTest.cpp",
"SurfaceFlinger_CreateDisplayTest.cpp",
"SurfaceFlinger_DestroyDisplayTest.cpp",
"SurfaceFlinger_DisplayModeSwitching.cpp",
diff --git a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp
new file mode 100644
index 0000000..b910485
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SmallAreaDetectionAllowMappingsTest"
+
+#include <gtest/gtest.h>
+
+#include "Scheduler/SmallAreaDetectionAllowMappings.h"
+
+namespace android::scheduler {
+
+class SmallAreaDetectionMappingsAllowTest : public testing::Test {
+protected:
+ SmallAreaDetectionAllowMappings mMappings;
+};
+
+namespace {
+TEST_F(SmallAreaDetectionMappingsAllowTest, testUpdate) {
+ const uid_t uid1 = 10100;
+ const uid_t uid2 = 10101;
+ const float threshold1 = 0.05f;
+ const float threshold2 = 0.07f;
+ std::vector<std::pair<uid_t, float>> mappings;
+ mappings.reserve(2);
+ mappings.push_back(std::make_pair(uid1, threshold1));
+ mappings.push_back(std::make_pair(uid2, threshold2));
+
+ mMappings.update(mappings);
+ ASSERT_EQ(mMappings.getThresholdForUid(uid1).value(), threshold1);
+ ASSERT_EQ(mMappings.getThresholdForUid(uid2).value(), threshold2);
+}
+
+TEST_F(SmallAreaDetectionMappingsAllowTest, testSetThesholdForUid) {
+ const uid_t uid = 10111;
+ const float threshold = 0.05f;
+
+ mMappings.setThesholdForUid(uid, threshold);
+ ASSERT_EQ(mMappings.getThresholdForUid(uid), threshold);
+}
+
+TEST_F(SmallAreaDetectionMappingsAllowTest, testUidNotInTheMappings) {
+ const uid_t uid = 10222;
+ ASSERT_EQ(mMappings.getThresholdForUid(uid), std::nullopt);
+}
+
+} // namespace
+} // namespace android::scheduler