diff options
17 files changed, 276 insertions, 11 deletions
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 92589c5742..4719e246e7 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2768,6 +2768,20 @@ status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) 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 c2f47fc5ba..1c604a1f8b 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -479,6 +479,15 @@ interface ISurfaceComposer { */ 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); + /** * Enables or disables the frame rate overlay in the top left corner. * Requires root or android.permission.HARDWARE_TEST diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 2643fa7d68..177d5f89c9 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -154,6 +154,9 @@ public: MOCK_METHOD(binder::Status, setDebugFlash, (int), (override)); MOCK_METHOD(binder::Status, scheduleComposite, (), (override)); MOCK_METHOD(binder::Status, scheduleCommit, (), (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 fd9f186663..6fef5d2378 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -203,6 +203,16 @@ public: // 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 ffb8622f39..daed764cd6 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -999,6 +999,15 @@ public: binder::Status scheduleCommit() override { 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 0101c1712a..eda52bfcb5 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -187,6 +187,7 @@ filegroup { "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 8f785a044c..077ed674ad 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -4388,7 +4388,8 @@ void Layer::setIsSmallDirty() { // 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()); } } // namespace android diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 13cf764746..c92e670aa9 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -306,9 +306,9 @@ auto LayerHistory::findLayer(int32_t id) -> std::pair<LayerStatus, LayerPair*> { 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 562bb4cace..5750ea7898 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -85,14 +85,12 @@ public: // return the frames per second of the layer with the given sequence id. float getLayerFramerate(nsecs_t now, int32_t id) const; - 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 5a19ec5095..27c96f7d4f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -1179,4 +1179,20 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid 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 ec20610f81..d65df2a65d 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" @@ -291,6 +292,13 @@ public: 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); @@ -314,11 +322,6 @@ public: 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; @@ -557,6 +560,7 @@ private: 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 0000000000..95cd5d199a --- /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 0000000000..cbab69091f --- /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 940a4c6b66..bc626f3030 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -8200,6 +8200,17 @@ status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { 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) { @@ -9532,6 +9543,40 @@ binder::Status SurfaceComposerAIDL::scheduleCommit() { return binder::Status::ok(); } +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 6ff9fd1111..79dcd0d1b2 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -607,6 +607,10 @@ private: 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; @@ -1557,6 +1561,9 @@ public: binder::Status setDebugFlash(int delay) override; binder::Status scheduleComposite() override; binder::Status scheduleCommit() 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 7d8796f71c..8deff85118 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -101,6 +101,7 @@ cc_test { "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 0000000000..b910485c06 --- /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 |