From 6d7cb59052a5bac6818da557bde6adf85edeccee Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Wed, 13 Mar 2019 15:07:57 +0900 Subject: [PATCH] Create writer and handle environment variable To handle better with generating configuration and resolving variables, new modules are introduced - ConfigWriter and Variables. Bug: 123722631 Test: m -j && atest Change-Id: Ibd44d5f93d566ce6d9bc04d474de83ec1e5e8ff4 --- include/linkerconfig/configwriter.h | 42 ++++++++++++++ include/linkerconfig/link.h | 5 +- include/linkerconfig/log.h | 20 +++++++ include/linkerconfig/namespace.h | 9 +-- include/linkerconfig/section.h | 7 ++- include/linkerconfig/variables.h | 35 ++++++++++++ modules/configwriter.cc | 109 ++++++++++++++++++++++++++++++++++++ modules/link.cc | 16 +++--- modules/namespace.cc | 43 +++++++------- modules/section.cc | 21 +++---- modules/tests/configwriter_test.cc | 73 ++++++++++++++++++++++++ modules/tests/link_test.cc | 14 ++++- modules/tests/namespace_test.cc | 11 +++- modules/tests/section_test.cc | 14 ++++- modules/tests/variables_test.cc | 48 ++++++++++++++++ modules/variables.cc | 51 +++++++++++++++++ 16 files changed, 458 insertions(+), 60 deletions(-) create mode 100644 include/linkerconfig/configwriter.h create mode 100644 include/linkerconfig/log.h create mode 100644 include/linkerconfig/variables.h create mode 100644 modules/configwriter.cc create mode 100644 modules/tests/configwriter_test.cc create mode 100644 modules/tests/variables_test.cc create mode 100644 modules/variables.cc diff --git a/include/linkerconfig/configwriter.h b/include/linkerconfig/configwriter.h new file mode 100644 index 0000000..9bc0f5f --- /dev/null +++ b/include/linkerconfig/configwriter.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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 +#include + +namespace android { +namespace linkerconfig { +namespace modules { + +class ConfigWriter { + public: + void SetPrefix(const std::string& prefix); + void ResetPrefix(); + void WriteLine(const std::string& line); + void WriteLine(const char* format, ...); + std::string ToString(); + + private: + std::stringstream content_; + std::string prefix_; + + std::string ResolveVariables(const std::string& str); +}; + +} // namespace modules +} // namespace linkerconfig +} // namespace android \ No newline at end of file diff --git a/include/linkerconfig/link.h b/include/linkerconfig/link.h index fada5b3..ed8d8a8 100644 --- a/include/linkerconfig/link.h +++ b/include/linkerconfig/link.h @@ -19,7 +19,8 @@ #include #include -#include +#include "linkerconfig/configwriter.h" +#include "linkerconfig/log.h" #define LOG_TAG "linkerconfig" @@ -36,7 +37,7 @@ class Link { } template void AddSharedLib(T&& lib_name, Args&&... lib_names); - std::string GenerateConfig(); + void WriteConfig(ConfigWriter& writer); private: const std::string origin_namespace_; diff --git a/include/linkerconfig/log.h b/include/linkerconfig/log.h new file mode 100644 index 0000000..ccc8bbd --- /dev/null +++ b/include/linkerconfig/log.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2019 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 + +#define LOG_TAG "linkerconfig" diff --git a/include/linkerconfig/namespace.h b/include/linkerconfig/namespace.h index 0ad4b9a..3e8c1bf 100644 --- a/include/linkerconfig/namespace.h +++ b/include/linkerconfig/namespace.h @@ -19,7 +19,8 @@ #include #include -#include "link.h" +#include "linkerconfig/configwriter.h" +#include "linkerconfig/link.h" namespace android { namespace linkerconfig { @@ -71,7 +72,7 @@ class Namespace { bool with_data_asan = true); std::shared_ptr CreateLink(const std::string& target_namespace, bool allow_all_shared_libs = false); - std::string GenerateConfig(); + void WriteConfig(ConfigWriter& writer); private: const bool is_isolated_; @@ -82,8 +83,8 @@ class Namespace { std::vector asan_search_paths_; std::vector asan_permitted_paths_; std::map> links_; - std::string GetPathString(const std::string& path_type, - const std::vector& path_list); + void WritePathString(ConfigWriter& writer, const std::string& path_type, + const std::vector& path_list); }; } // namespace modules } // namespace linkerconfig diff --git a/include/linkerconfig/section.h b/include/linkerconfig/section.h index d5e37c6..b5ac994 100644 --- a/include/linkerconfig/section.h +++ b/include/linkerconfig/section.h @@ -21,7 +21,8 @@ #include #include -#include "namespace.h" +#include "linkerconfig/configwriter.h" +#include "linkerconfig/namespace.h" namespace android { namespace linkerconfig { @@ -35,8 +36,8 @@ class Section { std::shared_ptr CreateNamespace(const std::string& namespace_name, bool is_isolated = false, bool is_visible = false); - std::string GenerateConfig(); - std::string GenerateBinaryPaths(); + void WriteConfig(ConfigWriter& writer); + void WriteBinaryPaths(ConfigWriter& writer); std::string GetName(); private: diff --git a/include/linkerconfig/variables.h b/include/linkerconfig/variables.h new file mode 100644 index 0000000..7c2c87f --- /dev/null +++ b/include/linkerconfig/variables.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 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 +#include +#include + +namespace android { +namespace linkerconfig { +namespace modules { +class Variables { + public: + static std::optional GetValue(const std::string& key); + static void AddValue(const std::string& key, const std::string& value); + + private: + static std::map variables_; +}; +} // namespace modules +} // namespace linkerconfig +} // namespace android \ No newline at end of file diff --git a/modules/configwriter.cc b/modules/configwriter.cc new file mode 100644 index 0000000..aed8abf --- /dev/null +++ b/modules/configwriter.cc @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2019 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 "linkerconfig/configwriter.h" + +#include +#include +#include +#include +#include + +#include "linkerconfig/log.h" +#include "linkerconfig/variables.h" + +constexpr const char* kVariableRegex = + "@\\{([^@\\{\\}:]+)(:([^@\\{\\}:]*))?\\}"; + +namespace android { +namespace linkerconfig { +namespace modules { + +void ConfigWriter::SetPrefix(const std::string& prefix) { + prefix_ = prefix; +} + +void ConfigWriter::ResetPrefix() { + prefix_ = ""; +} + +void ConfigWriter::WriteLine(const char* format, ...) { + va_list args_for_length, args; + + va_start(args, format); + va_copy(args_for_length, args); + + int length = vsnprintf(nullptr, 0, format, args_for_length); + va_end(args_for_length); + + if (length < 0) { + LOG(ERROR) << "Failed to get length of the string with format " << format; + va_end(args); + return; + } + + std::unique_ptr formatted_string(new char[length + 1]); + + int res = vsnprintf(formatted_string.get(), length + 1, format, args); + va_end(args); + + if (res < 0) { + LOG(ERROR) << "Failed to write a string with format " << format; + return; + } + + WriteLine(std::string(formatted_string.get())); +} + +void ConfigWriter::WriteLine(const std::string& line) { + auto resolved_line = ResolveVariables(prefix_ + line); + content_ << resolved_line << std::endl; +} + +std::string ConfigWriter::ToString() { + return content_.str(); +} + +std::string ConfigWriter::ResolveVariables(const std::string& str) { + std::string result = str; + std::regex variable_regex(kVariableRegex); + std::smatch sm; + + while (std::regex_search(result, sm, variable_regex)) { + std::stringstream ss; + ss << sm.prefix(); + auto resolved_value = Variables::GetValue(sm[1]); + if (resolved_value.has_value()) { + ss << resolved_value.value(); + } else { + LOG(WARNING) << "Unable to find value for " << sm[1]; + bool contains_default = sm[2].length() > 0; + if (contains_default) { + ss << sm[3]; + } else { + LOG(FATAL) << "There is no default value defined for " << sm[1]; + } + } + ss << ResolveVariables(sm.suffix()); + result = ss.str(); + } + + return result; +} + +} // namespace modules +} // namespace linkerconfig +} // namespace android \ No newline at end of file diff --git a/modules/link.cc b/modules/link.cc index 133cd57..64dddda 100644 --- a/modules/link.cc +++ b/modules/link.cc @@ -19,23 +19,21 @@ namespace android { namespace linkerconfig { namespace modules { -std::string Link::GenerateConfig() { - std::string prefix = - "namespace." + origin_namespace_ + ".link." + target_namespace_; - std::string config = ""; +void Link::WriteConfig(ConfigWriter& writer) { + writer.SetPrefix("namespace." + origin_namespace_ + ".link." + + target_namespace_); if (allow_all_shared_libs_) { - config = prefix + ".allow_all_shared_libs = true\n"; + writer.WriteLine(".allow_all_shared_libs = true"); } else { bool is_first = true; for (auto& lib_name : shared_libs_) { - config += prefix + ".shared_libs " + (is_first ? "= " : "+= ") + - lib_name + "\n"; + writer.WriteLine(".shared_libs %s %s", + is_first ? "=" : "+=", lib_name.c_str()); is_first = false; } } - - return config; + writer.ResetPrefix(); } } // namespace modules } // namespace linkerconfig diff --git a/modules/namespace.cc b/modules/namespace.cc index c2c3ea2..486691c 100644 --- a/modules/namespace.cc +++ b/modules/namespace.cc @@ -16,7 +16,7 @@ #include "linkerconfig/namespace.h" -#include +#include "linkerconfig/log.h" #define LOG_TAG "linkerconfig" @@ -26,17 +26,15 @@ namespace modules { constexpr const char* kDataAsanPath = "/data/asan"; -std::string Namespace::GetPathString(const std::string& path_type, - const std::vector& path_list) { - std::string prefix = "namespace." + name_ + "." + path_type + ".paths "; - std::string path_string = ""; +void Namespace::WritePathString(ConfigWriter& writer, + const std::string& path_type, + const std::vector& path_list) { + std::string prefix = path_type + ".paths "; bool is_first = true; for (auto& path : path_list) { - path_string += prefix + (is_first ? "= " : "+= ") + path + "\n"; + writer.WriteLine(prefix + (is_first ? "= " : "+= ") + path); is_first = false; } - - return path_string; } std::shared_ptr Namespace::CreateLink(const std::string& target_namespace, @@ -53,41 +51,40 @@ std::shared_ptr Namespace::CreateLink(const std::string& target_namespace, return new_link; } -std::string Namespace::GenerateConfig() { - std::string config = ""; - std::string prefix = "namespace." + name_ + "."; +void Namespace::WriteConfig(ConfigWriter& writer) { + writer.SetPrefix("namespace." + name_ + "."); - config += prefix + "isolated = " + (is_isolated_ ? "true" : "false") + "\n"; + writer.WriteLine("isolated = %s", is_isolated_ ? "true" : "false"); if (is_visible_) { - config += prefix + "visible = true\n"; + writer.WriteLine("visible = true"); } - config += GetPathString("search", search_paths_); - config += GetPathString("permitted", permitted_paths_); - config += GetPathString("asan.search", asan_search_paths_); - config += GetPathString("asan.permitted", asan_permitted_paths_); + WritePathString(writer, "search", search_paths_); + WritePathString(writer, "permitted", permitted_paths_); + WritePathString(writer, "asan.search", asan_search_paths_); + WritePathString(writer, "asan.permitted", asan_permitted_paths_); if (!links_.empty()) { - config += prefix + "links = "; + std::string link_list = ""; bool is_first = true; for (auto& link : links_) { if (!is_first) { - config += ","; + link_list += ","; } - config += link.first; + link_list += link.first; is_first = false; } - config += "\n"; + writer.WriteLine("links = " + link_list); for (auto& link : links_) { - config += link.second->GenerateConfig(); + link.second->WriteConfig(writer); } } - return config; + writer.ResetPrefix(); } void Namespace::AddSearchPath(const std::string& path, bool in_asan, diff --git a/modules/section.cc b/modules/section.cc index 5501ce3..98c3a94 100644 --- a/modules/section.cc +++ b/modules/section.cc @@ -16,7 +16,7 @@ #include "linkerconfig/section.h" -#include +#include "linkerconfig/log.h" #define LOG_TAG "linkerconfig" @@ -37,8 +37,8 @@ std::shared_ptr Section::CreateNamespace( return new_namespace; } -std::string Section::GenerateConfig() { - std::string config = "[" + name_ + "]\n"; +void Section::WriteConfig(ConfigWriter& writer) { + writer.WriteLine("[%s]", name_.c_str()); std::string additional_namespaces = ""; @@ -55,25 +55,22 @@ std::string Section::GenerateConfig() { } if (!is_first) { - config += "additional.namespaces = " + additional_namespaces + "\n"; + writer.WriteLine("additional.namespaces = " + additional_namespaces); } for (auto& ns : namespaces_) { - config += ns.second->GenerateConfig(); + ns.second->WriteConfig(writer); } - - return config; } -std::string Section::GenerateBinaryPaths() { - std::string binary_path = ""; - std::string prefix = "dir." + name_ + " = "; +void Section::WriteBinaryPaths(ConfigWriter& writer) { + writer.SetPrefix("dir." + name_ + " = "); for (auto& path : binary_paths_) { - binary_path += prefix + path + "\n"; + writer.WriteLine(path); } - return binary_path; + writer.ResetPrefix(); } std::string Section::GetName() { diff --git a/modules/tests/configwriter_test.cc b/modules/tests/configwriter_test.cc new file mode 100644 index 0000000..4c5c9fa --- /dev/null +++ b/modules/tests/configwriter_test.cc @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 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 + +#include "linkerconfig/configwriter.h" +#include "linkerconfig/variables.h" + +constexpr const char* kSampleContent = "Lorem ipsum dolor sit amet"; + +constexpr const char* kExpectedResultWithPrefix = + R"(Lorem ipsum dolor sit amet +SAMPLE.TEST.Text : Lorem ipsum dolor sit amet +end of context +)"; + +constexpr const char* kExpectedResultWithVariables = + R"(/Value/Test +/Invalid_Value/Path +//Path2 +)"; + +TEST(linkerconfig_configwriter, write_line) { + android::linkerconfig::modules::ConfigWriter writer; + + writer.WriteLine(kSampleContent); + + ASSERT_EQ(writer.ToString(), "Lorem ipsum dolor sit amet\n"); +} + +TEST(linkerconfig_configwriter, write_with_format) { + android::linkerconfig::modules::ConfigWriter writer; + writer.WriteLine("Sample text(%d) : %s", 10, kSampleContent); + ASSERT_EQ(writer.ToString(), + "Sample text(10) : Lorem ipsum dolor sit amet\n"); +} + +TEST(linkerconfig_configwriter, write_with_prefix) { + android::linkerconfig::modules::ConfigWriter writer; + writer.WriteLine(kSampleContent); + writer.SetPrefix("SAMPLE.TEST."); + writer.WriteLine("Text : %s", kSampleContent); + writer.ResetPrefix(); + writer.WriteLine("end of context"); + + ASSERT_EQ(writer.ToString(), kExpectedResultWithPrefix); +} + +TEST(linkerconfig_configwriter, replace_variable) { + android::linkerconfig::modules::ConfigWriter writer; + + android::linkerconfig::modules::Variables::AddValue("Test_Prop_Q", "Value"); + android::linkerconfig::modules::Variables::AddValue("VNDK_VER", "Q"); + + writer.WriteLine("/@{Test_Prop_@{VNDK_VER}}/Test"); + writer.WriteLine("/@{Invalid_Key:Invalid_Value}/Path"); + writer.WriteLine("/@{Invalid_Key:}/Path2"); + + ASSERT_EQ(writer.ToString(), kExpectedResultWithVariables); +} \ No newline at end of file diff --git a/modules/tests/link_test.cc b/modules/tests/link_test.cc index d84e3b4..a467ba4 100644 --- a/modules/tests/link_test.cc +++ b/modules/tests/link_test.cc @@ -16,6 +16,7 @@ #include +#include "linkerconfig/configwriter.h" #include "linkerconfig/link.h" constexpr const char* kSharedLibsExpectedResult = @@ -25,18 +26,27 @@ namespace.originalNamespace.link.targetNamespace.shared_libs += lib3.so )"; TEST(linkerconfig_link, link_with_all_shared_libs) { + android::linkerconfig::modules::ConfigWriter writer; + auto link = std::make_shared( "originalNamespace", "targetNamespace", true); - auto config_text = link->GenerateConfig(); + + link->WriteConfig(writer); + auto config_text = writer.ToString(); + ASSERT_EQ(config_text, "namespace.originalNamespace.link.targetNamespace.allow_all_shared_" "libs = true\n"); } TEST(linkerconfig_link, link_with_shared_libs) { + android::linkerconfig::modules::ConfigWriter writer; auto link = std::make_shared( "originalNamespace", "targetNamespace"); link->AddSharedLib("lib1.so", "lib2.so", "lib3.so"); - auto config_text = link->GenerateConfig(); + + link->WriteConfig(writer); + auto config_text = writer.ToString(); + ASSERT_EQ(config_text, kSharedLibsExpectedResult); } \ No newline at end of file diff --git a/modules/tests/namespace_test.cc b/modules/tests/namespace_test.cc index e6a70eb..777d8d7 100644 --- a/modules/tests/namespace_test.cc +++ b/modules/tests/namespace_test.cc @@ -16,6 +16,7 @@ #include +#include "linkerconfig/configwriter.h" #include "modules_testbase.h" constexpr const char* kExpectedSimpleNamespaceConfig = @@ -57,21 +58,27 @@ namespace.test_namespace.link.target_namespace2.allow_all_shared_libs = true )"; TEST(linkerconfig_namespace, simple_namespace) { + android::linkerconfig::modules::ConfigWriter writer; auto ns = std::make_shared( "test_namespace"); + DecorateNamespaceWithPaths(ns); - auto config = ns->GenerateConfig(); + ns->WriteConfig(writer); + auto config = writer.ToString(); ASSERT_EQ(config, kExpectedSimpleNamespaceConfig); } TEST(linkerconfig_namespace, namespace_with_links) { + android::linkerconfig::modules::ConfigWriter writer; auto ns = std::make_shared( "test_namespace", /*is_isolated*/ true, /*is_visible*/ true); + DecorateNamespaceWithPaths(ns); DecorateNamespaceWithLinks(ns, "target_namespace1", "target_namespace2"); - auto config = ns->GenerateConfig(); + ns->WriteConfig(writer); + auto config = writer.ToString(); ASSERT_EQ(config, kExpectedNamespaceWithLinkConfig); } \ No newline at end of file diff --git a/modules/tests/section_test.cc b/modules/tests/section_test.cc index 697e595..bba62a4 100644 --- a/modules/tests/section_test.cc +++ b/modules/tests/section_test.cc @@ -16,6 +16,7 @@ #include +#include "linkerconfig/configwriter.h" #include "linkerconfig/section.h" #include "modules_testbase.h" @@ -96,7 +97,9 @@ constexpr const char* kSectionBinaryPathExpectedResult = dir.test_section = binary_path2 dir.test_section = binary_path3 )"; + TEST(linkerconfig_section, section_with_namespaces) { + android::linkerconfig::modules::ConfigWriter writer; android::linkerconfig::modules::Section section("test_section"); auto default_namespace = section.CreateNamespace( @@ -111,23 +114,28 @@ TEST(linkerconfig_section, section_with_namespaces) { auto namespace2 = section.CreateNamespace("namespace2"); DecorateNamespaceWithPaths(namespace2); - auto config = section.GenerateConfig(); + section.WriteConfig(writer); + auto config = writer.ToString(); ASSERT_EQ(config, kSectionWithNamespacesExpectedResult); } TEST(linkerconfig_section, section_with_one_namespace) { + android::linkerconfig::modules::ConfigWriter writer; android::linkerconfig::modules::Section section("test_section"); auto ns = section.CreateNamespace("default"); DecorateNamespaceWithPaths(ns); - auto config = section.GenerateConfig(); + section.WriteConfig(writer); + auto config = writer.ToString(); ASSERT_EQ(config, kSectionWithOneNamespaceExpectedResult); } TEST(linkerconfig_section, binary_paths) { + android::linkerconfig::modules::ConfigWriter writer; android::linkerconfig::modules::Section section("test_section"); section.AddBinaryPath("binary_path1", "binary_path2", "binary_path3"); - auto binary_paths = section.GenerateBinaryPaths(); + section.WriteBinaryPaths(writer); + auto binary_paths = writer.ToString(); ASSERT_EQ(binary_paths, kSectionBinaryPathExpectedResult); } \ No newline at end of file diff --git a/modules/tests/variables_test.cc b/modules/tests/variables_test.cc new file mode 100644 index 0000000..e4ada44 --- /dev/null +++ b/modules/tests/variables_test.cc @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 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 +#include +#include + +#include "linkerconfig/variables.h" + +using android::linkerconfig::modules::Variables; + +TEST(linkerconfig_variables, load_from_map) { + Variables::AddValue("TEST_KEY", "TEST_VALUE"); + auto value = Variables::GetValue("TEST_KEY"); + ASSERT_TRUE(value.has_value()); + ASSERT_EQ(value.value(), "TEST_VALUE"); +} + +TEST(linkerconfig_variables, load_from_property) { +#if defined(__BIONIC__) + android::base::SetProperty("debug.linkerconfig.test_prop_key", + "TEST_PROP_VALUE"); + ASSERT_TRUE(android::base::WaitForProperty("debug.linkerconfig.test_prop_key", + "TEST_PROP_VALUE", + std::chrono::seconds(1))); + auto value = Variables::GetValue("debug.linkerconfig.test_prop_key"); + ASSERT_TRUE(value.has_value()); + ASSERT_EQ(value.value(), "TEST_PROP_VALUE"); +#endif +} + +TEST(linkerconfig_variables, fallback_value) { + auto value = Variables::GetValue("INVALID_KEY"); + ASSERT_FALSE(value.has_value()); +} \ No newline at end of file diff --git a/modules/variables.cc b/modules/variables.cc new file mode 100644 index 0000000..fcc41ee --- /dev/null +++ b/modules/variables.cc @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 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 "linkerconfig/variables.h" + +#include + +#include "linkerconfig/log.h" + +namespace android { +namespace linkerconfig { +namespace modules { + +std::map Variables::variables_; + +std::optional Variables::GetValue(const std::string& variable) { + // If variable is in predefined key-value pair, use this value + if (variables_.find(variable) != variables_.end() && + !variables_[variable].empty()) { + return {variables_[variable]}; + } + + // If variable is defined as property, use this value + std::string prop_value = android::base::GetProperty(variable, ""); + if (!prop_value.empty()) { + return {prop_value}; + } + + // If cannot find variable, return default value + return std::nullopt; +} + +void Variables::AddValue(const std::string& key, const std::string& value) { + variables_[key] = value; +} +} // namespace modules +} // namespace linkerconfig +} // namespace android \ No newline at end of file -- 2.11.0