diff options
| -rw-r--r-- | services/surfaceflinger/Android.bp | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/FlagManager.cpp | 93 | ||||
| -rw-r--r-- | services/surfaceflinger/FlagManager.h | 44 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/Android.bp | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/FlagManagerTest.cpp | 143 |
5 files changed, 284 insertions, 0 deletions
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index eeb3f3a288..af012cd11c 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -66,6 +66,7 @@ cc_defaults { "libinput", "libutils", "libSurfaceFlingerProp", + "server_configurable_flags", ], static_libs: [ "libcompositionengine", @@ -154,6 +155,7 @@ filegroup { "DisplayRenderArea.cpp", "Effects/Daltonizer.cpp", "EventLog/EventLog.cpp", + "FlagManager.cpp", "FpsReporter.cpp", "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp new file mode 100644 index 0000000000..f0c5b583cf --- /dev/null +++ b/services/surfaceflinger/FlagManager.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 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 "FlagManager.h" + +#include <SurfaceFlingerProperties.sysprop.h> +#include <android-base/parsebool.h> +#include <android-base/parseint.h> +#include <android-base/stringprintf.h> +#include <log/log.h> +#include <server_configurable_flags/get_flags.h> +#include <cinttypes> + +namespace android { +static constexpr const char* kExperimentNamespace = "surface_flinger_native_boot"; +static constexpr const int64_t kDemoFlag = -1; + +FlagManager::~FlagManager() = default; + +void FlagManager::dump(std::string& result) const { + base::StringAppendF(&result, "FlagManager values: \n"); + base::StringAppendF(&result, "demo_flag: %" PRId64 "\n", demo_flag()); +} + +namespace { +template <typename T> +std::optional<T> doParse(const char* str); + +template <> +[[maybe_unused]] std::optional<int32_t> doParse(const char* str) { + int32_t ret; + return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt; +} + +template <> +[[maybe_unused]] std::optional<int64_t> doParse(const char* str) { + int64_t ret; + return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt; +} + +template <> +[[maybe_unused]] std::optional<bool> doParse(const char* str) { + base::ParseBoolResult parseResult = base::ParseBool(str); + switch (parseResult) { + case base::ParseBoolResult::kTrue: + return std::make_optional(true); + case base::ParseBoolResult::kFalse: + return std::make_optional(false); + case base::ParseBoolResult::kError: + return std::nullopt; + } +} +} // namespace + +std::string FlagManager::getServerConfigurableFlag(const std::string& experimentFlagName) const { + return server_configurable_flags::GetServerConfigurableFlag(kExperimentNamespace, + experimentFlagName, ""); +} + +template int32_t FlagManager::getValue<int32_t>(const std::string&, std::optional<int32_t>, + int32_t) const; +template int64_t FlagManager::getValue<int64_t>(const std::string&, std::optional<int64_t>, + int64_t) const; +template bool FlagManager::getValue<bool>(const std::string&, std::optional<bool>, bool) const; +template <typename T> +T FlagManager::getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt, + T defaultValue) const { + // System property takes precedence over the experiment config server value. + if (systemPropertyOpt.has_value()) { + return *systemPropertyOpt; + } + std::string str = getServerConfigurableFlag(experimentFlagName); + return str.empty() ? defaultValue : doParse<T>(str.c_str()).value_or(defaultValue); +} + +int64_t FlagManager::demo_flag() const { + std::optional<int64_t> sysPropVal = std::nullopt; + return getValue("DemoFeature__demo_flag", sysPropVal, kDemoFlag); +} +} // namespace android diff --git a/services/surfaceflinger/FlagManager.h b/services/surfaceflinger/FlagManager.h new file mode 100644 index 0000000000..65e30a45be --- /dev/null +++ b/services/surfaceflinger/FlagManager.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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 <cstdint> +#include <optional> +#include <string> + +namespace android { +// Manages flags for SurfaceFlinger, including default values, system properties, and Mendel +// experiment configuration values. +class FlagManager { +public: + FlagManager() = default; + virtual ~FlagManager(); + void dump(std::string& result) const; + + int64_t demo_flag() const; + +private: + friend class FlagManagerTest; + + // Wrapper for mocking in test. + virtual std::string getServerConfigurableFlag(const std::string& experimentFlagName) const; + + template <typename T> + T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt, + T defaultValue) const; +}; +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 200ecbd894..078b0d4ef3 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -57,6 +57,7 @@ cc_test { "DisplayDevice_InitiateModeChange.cpp", "DisplayDevice_SetProjectionTest.cpp", "EventThreadTest.cpp", + "FlagManagerTest.cpp", "FpsReporterTest.cpp", "FpsTest.cpp", "FramebufferSurfaceTest.cpp", @@ -164,6 +165,7 @@ cc_test { "libsync", "libui", "libutils", + "server_configurable_flags", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp new file mode 100644 index 0000000000..0905cd14b1 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2021 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 <cstdint> +#undef LOG_TAG +#define LOG_TAG "FlagManagerTest" + +#include "FlagManager.h" + +#include <android-base/properties.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <log/log.h> +#include <server_configurable_flags/get_flags.h> +#include <optional> + +namespace android { + +using testing::Return; + +class MockFlagManager : public FlagManager { +public: + MockFlagManager() = default; + ~MockFlagManager() = default; + + MOCK_METHOD(std::string, getServerConfigurableFlag, (const std::string& experimentFlagName), + (const, override)); +}; + +class FlagManagerTest : public testing::Test { +public: + FlagManagerTest(); + ~FlagManagerTest() override; + std::unique_ptr<MockFlagManager> mFlagManager; + + template <typename T> + T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt, + T defaultValue); +}; + +FlagManagerTest::FlagManagerTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + mFlagManager = std::make_unique<MockFlagManager>(); +} + +FlagManagerTest::~FlagManagerTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); +} + +template <typename T> +T FlagManagerTest::getValue(const std::string& experimentFlagName, + std::optional<T> systemPropertyOpt, T defaultValue) { + return mFlagManager->getValue(experimentFlagName, systemPropertyOpt, defaultValue); +} + +namespace { +TEST_F(FlagManagerTest, getValue_bool_default) { + EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("")); + const bool defaultValue = false; + std::optional<bool> systemPropertyValue = std::nullopt; + const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); + ASSERT_EQ(result, defaultValue); +} + +TEST_F(FlagManagerTest, getValue_bool_sysprop) { + const bool defaultValue = false; + std::optional<bool> systemPropertyValue = std::make_optional(true); + const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); + ASSERT_EQ(result, true); +} + +TEST_F(FlagManagerTest, getValue_bool_experiment) { + EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("1")); + const bool defaultValue = false; + std::optional<bool> systemPropertyValue = std::nullopt; + const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); + ASSERT_EQ(result, true); +} + +TEST_F(FlagManagerTest, getValue_int32_default) { + EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("")); + int32_t defaultValue = 30; + std::optional<int32_t> systemPropertyValue = std::nullopt; + int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); + ASSERT_EQ(result, defaultValue); +} + +TEST_F(FlagManagerTest, getValue_int32_sysprop) { + int32_t defaultValue = 30; + std::optional<int32_t> systemPropertyValue = std::make_optional(10); + int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); + ASSERT_EQ(result, 10); +} + +TEST_F(FlagManagerTest, getValue_int32_experiment) { + EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50")); + std::int32_t defaultValue = 30; + std::optional<std::int32_t> systemPropertyValue = std::nullopt; + std::int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); + ASSERT_EQ(result, 50); +} + +TEST_F(FlagManagerTest, getValue_int64_default) { + EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("")); + int64_t defaultValue = 30; + std::optional<int64_t> systemPropertyValue = std::nullopt; + int64_t result = getValue("flag_name", systemPropertyValue, defaultValue); + ASSERT_EQ(result, defaultValue); +} + +TEST_F(FlagManagerTest, getValue_int64_sysprop) { + int64_t defaultValue = 30; + std::optional<int64_t> systemPropertyValue = std::make_optional(10); + int64_t result = getValue("flag_name", systemPropertyValue, defaultValue); + ASSERT_EQ(result, 10); +} + +TEST_F(FlagManagerTest, getValue_int64_experiment) { + EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50")); + int64_t defaultValue = 30; + std::optional<int64_t> systemPropertyValue = std::nullopt; + int64_t result = getValue("flag_name", systemPropertyValue, defaultValue); + ASSERT_EQ(result, 50); +} +} // namespace +} // namespace android |