summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmdline/cmdline_parser.h18
-rw-r--r--cmdline/cmdline_types.h17
-rw-r--r--libartbase/Android.bp2
-rw-r--r--libartbase/base/flags.cc147
-rw-r--r--libartbase/base/flags.h234
-rw-r--r--libartbase/base/flags_test.cc123
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc7
-rw-r--r--runtime/parsed_options.cc8
-rw-r--r--runtime/runtime.cc8
-rw-r--r--runtime/runtime.h11
10 files changed, 572 insertions, 3 deletions
diff --git a/cmdline/cmdline_parser.h b/cmdline/cmdline_parser.h
index 22eb44c211..7e343f8ef2 100644
--- a/cmdline/cmdline_parser.h
+++ b/cmdline/cmdline_parser.h
@@ -210,6 +210,24 @@ struct CmdlineParser {
return parent_;
}
+ // Write the results of this argument into a variable pointed to by destination.
+ // An optional is used to tell whether the command line argument was present.
+ CmdlineParser::Builder& IntoLocation(std::optional<TArg>* destination) {
+ save_value_ = [destination](TArg& value) {
+ *destination = value;
+ };
+
+ load_value_ = [destination]() -> TArg& {
+ return destination->value();
+ };
+
+ save_value_specified_ = true;
+ load_value_specified_ = true;
+
+ CompleteArgument();
+ return parent_;
+ }
+
// Ensure we always move this when returning a new builder.
ArgumentBuilder(ArgumentBuilder&&) = default;
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 43d30222c7..964e2385b6 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -21,6 +21,7 @@
#include <list>
#include <ostream>
+#include "android-base/parsebool.h"
#include "android-base/stringprintf.h"
#include "cmdline_type_parser.h"
#include "detail/cmdline_debug_detail.h"
@@ -67,6 +68,22 @@ struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
};
template <>
+struct CmdlineType<bool> : CmdlineTypeParser<bool> {
+ Result Parse(const std::string& args) {
+ switch (::android::base::ParseBool(args)) {
+ case ::android::base::ParseBoolResult::kError:
+ return Result::Failure("Could not parse '" + args + "' as boolean");
+ case ::android::base::ParseBoolResult::kTrue:
+ return Result::Success(true);
+ case ::android::base::ParseBoolResult::kFalse:
+ return Result::Success(false);
+ }
+ }
+
+ static const char* DescribeType() { return "true|false|1|0|y|n|yes|no|on|off"; }
+};
+
+template <>
struct CmdlineType<JdwpProvider> : CmdlineTypeParser<JdwpProvider> {
/*
* Handle a single JDWP provider name. Must be either 'internal', 'default', or the file name of
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 1b021195d6..9dcba9977c 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -37,6 +37,7 @@ cc_defaults {
"base/enums.cc",
"base/file_magic.cc",
"base/file_utils.cc",
+ "base/flags.cc",
"base/hex_dump.cc",
"base/hiddenapi_flags.cc",
"base/logging.cc",
@@ -260,6 +261,7 @@ art_cc_test {
"base/bit_vector_test.cc",
"base/compiler_filter_test.cc",
"base/file_utils_test.cc",
+ "base/flags_test.cc",
"base/hash_map_test.cc",
"base/hash_set_test.cc",
"base/hex_dump_test.cc",
diff --git a/libartbase/base/flags.cc b/libartbase/base/flags.cc
new file mode 100644
index 0000000000..46de9c0821
--- /dev/null
+++ b/libartbase/base/flags.cc
@@ -0,0 +1,147 @@
+/*
+ * 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 "flags.h"
+
+#include <algorithm>
+
+#include "android-base/parsebool.h"
+#include "android-base/parseint.h"
+#include "android-base/properties.h"
+
+#include "base/utils.h"
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wconversion"
+
+namespace {
+constexpr const char* kPhenotypeFlagPrefix = "persist.device_config.runtime_native.";
+constexpr const char* kSysPropertyFlagPrefix = "dalvik.vm.";
+constexpr const char* kUndefinedValue = "";
+
+// The various ParseValue functions store the parsed value into *destination. If parsing fails for
+// some reason, ParseValue makes no changes to *destination.
+
+void ParseValue(const std::string_view value, std::optional<bool>* destination) {
+ switch (::android::base::ParseBool(value)) {
+ case ::android::base::ParseBoolResult::kError:
+ return;
+ case ::android::base::ParseBoolResult::kTrue:
+ *destination = true;
+ return;
+ case ::android::base::ParseBoolResult::kFalse:
+ *destination = false;
+ return;
+ }
+}
+
+void ParseValue(const std::string_view value, std::optional<int>* destination) {
+ int parsed_value = 0;
+ if (::android::base::ParseInt(std::string{value}, &parsed_value)) {
+ *destination = parsed_value;
+ }
+}
+
+void ParseValue(const std::string_view value, std::optional<std::string>* destination) {
+ *destination = value;
+}
+
+} // namespace
+
+namespace art {
+
+template <>
+std::forward_list<FlagBase*> FlagBase::ALL_FLAGS{};
+
+// gFlags must be defined after FlagBase::ALL_FLAGS so the constructors run in the right order.
+Flags gFlags;
+
+static std::string GenerateCmdLineArgName(const std::string& name) {
+ std::string result = "-X" + name + ":_";
+ std::replace(result.begin(), result.end(), '.', '-');
+ return result;
+}
+
+static std::string GenerateSysPropName(const std::string& name) {
+ return kSysPropertyFlagPrefix + name;
+}
+
+static std::string GeneratePhenotypeName(const std::string& name) {
+ return kPhenotypeFlagPrefix + name;
+}
+
+template <typename Value>
+Flag<Value>::Flag(const std::string& name, Value default_value) :
+ FlagBase(GenerateCmdLineArgName(name),
+ GenerateSysPropName(name),
+ GeneratePhenotypeName(name)),
+ initialized_{false},
+ default_{default_value} {
+ ALL_FLAGS.push_front(this);
+}
+
+template <typename Value>
+void Flag<Value>::Reload() {
+ // The cmdline flags are loaded by the parsed_options infra.
+
+ // Load system properties.
+ from_system_property_ = std::nullopt;
+ const std::string sysprop = ::android::base::GetProperty(system_property_name_, kUndefinedValue);
+ if (sysprop != kUndefinedValue) {
+ ParseValue(sysprop, &from_system_property_);
+ }
+
+ // Load the server-side configuration.
+ from_server_setting_ = std::nullopt;
+ const std::string server_config =
+ ::android::base::GetProperty(server_setting_name_, kUndefinedValue);
+ if (server_config != kUndefinedValue) {
+ ParseValue(server_config, &from_server_setting_);
+ }
+
+ initialized_ = true;
+}
+
+template <typename Value>
+void DumpValue(std::ostream& oss, const std::optional<Value>& val) {
+ if (val.has_value()) {
+ oss << val.value();
+ } else {
+ oss << kUndefinedValue;
+ }
+}
+
+template <typename Value>
+void Flag<Value>::Dump(std::ostream& oss) const {
+ std::pair<Value, std::string> valueLoc = GetValueLocation();
+ oss << "value: " << std::get<0>(valueLoc) << " (from " << std::get<1>(valueLoc) << ")";
+
+ oss << "\n default: " << default_;
+ oss << "\n " << command_line_argument_name_ << ": ";
+ DumpValue(oss, from_command_line_);
+ oss << "\n " << system_property_name_ << ": ";
+ DumpValue(oss, from_system_property_);
+ oss << "\n " << server_setting_name_ << ": ";
+ DumpValue(oss, from_server_setting_);
+}
+
+template class Flag<bool>;
+template class Flag<int>;
+template class Flag<std::string>;
+
+} // namespace art
+
+#pragma clang diagnostic pop // -Wconversion
diff --git a/libartbase/base/flags.h b/libartbase/base/flags.h
new file mode 100644
index 0000000000..ae166e64a6
--- /dev/null
+++ b/libartbase/base/flags.h
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_LIBARTBASE_BASE_FLAGS_H_
+#define ART_LIBARTBASE_BASE_FLAGS_H_
+
+#include <forward_list>
+#include <optional>
+#include <string>
+#include <variant>
+
+#include "logging.h"
+
+// This file defines a set of flags that can be used to enable/disable features within ART or
+// otherwise tune ART's behavior. Flags can be set through command line options, server side
+// configuration, system properties, or default values. This flexibility enables easier development
+// and also larger experiments.
+//
+// The value is retrieved in the following oder:
+// 1) server side (device config) property
+// 2) system property
+// 3) cmdline flag
+// 4) default value
+//
+// The flags are defined in the Flags struct near the bottom of the file. To define a new flag, add
+// a Flag field to the struct. Then to read the value of the flag, use gFlag.MyNewFlag().
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wconversion"
+
+namespace art {
+
+// FlagMetaBase handles automatically adding flags to the command line parser. It is parameterized
+// by all supported flag types. In general, this should be treated as though it does not exist and
+// FlagBase, which is already specialized to the types we support, should be used instead.
+template <typename... T>
+class FlagMetaBase {
+ public:
+ FlagMetaBase(const std::string&& command_line_argument_name,
+ const std::string&& system_property_name,
+ const std::string&& server_setting_name) :
+ command_line_argument_name_(command_line_argument_name),
+ system_property_name_(system_property_name),
+ server_setting_name_(server_setting_name) {}
+ virtual ~FlagMetaBase() {}
+
+ template <typename Builder>
+ static void AddFlagsToCmdlineParser(Builder* builder) {
+ for (auto* flag : ALL_FLAGS) {
+ // Each flag can return a pointer to where its command line value is stored. Because these can
+ // be different types, the return value comes as a variant. The cases list below contains a
+ // lambda that is specialized to handle each branch of the variant and call the correct
+ // methods on the command line parser builder.
+ FlagValuePointer location = flag->GetCmdLineLocation();
+ auto cases = {std::function<void()>([&]() {
+ if (std::holds_alternative<std::optional<T>*>(location)) {
+ builder = &builder->Define(flag->command_line_argument_name_.c_str())
+ .template WithType<T>()
+ .IntoLocation(std::get<std::optional<T>*>(location));
+ }
+ })...};
+ for (auto c : cases) {
+ c();
+ }
+ }
+ }
+
+ // Reload the value of the flags.
+ //
+ // DO NOT CALL this outside Runtime Init or Zygote post fork.
+ // This is a convention, as we should strive to have a constant view
+ // of the flags and not change the runtime behaviour midway during execution.
+ static void ReloadAllFlags(const std::string& caller) {
+ // Check the caller. This is a simple workaround to attract the attention
+ // to a possible dangerous call to ReloadAllFlags, while avoid building
+ // a lot of infra for it or having a complex friend definition.
+ DCHECK(caller == "Init"
+ || caller == "ZygoteHooks_nativePostForkChild"
+ || caller == "ZygoteHooks_nativePostForkSystemServer"
+ || caller == "test") << caller;
+ for (auto* flag : ALL_FLAGS) {
+ flag->Reload();
+ }
+
+ if (VLOG_IS_ON(startup)) {
+ VLOG_STREAM(startup) << "Dumping flags for " << caller;
+ DumpFlags(VLOG_STREAM(startup));
+ }
+ }
+
+ // Dump all the flags info to the given stream.
+ static void DumpFlags(std::ostream& oss) {
+ for (auto* flag : ALL_FLAGS) {
+ oss << "\n{\n";
+ flag->Dump(oss);
+ oss << "\n}";
+ }
+ }
+
+ protected:
+ using FlagValuePointer = std::variant<std::optional<T>*...>;
+ // Return the pointer to the value holder associated with the cmd line location.
+ virtual FlagValuePointer GetCmdLineLocation() = 0;
+ // Reloads the flag values.
+ virtual void Reload() = 0;
+ // Dumps the flags info to the given stream.
+ virtual void Dump(std::ostream& oss) const = 0;
+
+ static std::forward_list<FlagMetaBase<T...>*> ALL_FLAGS;
+
+ const std::string command_line_argument_name_;
+ const std::string system_property_name_;
+ const std::string server_setting_name_;
+};
+
+using FlagBase = FlagMetaBase<bool, int, std::string>;
+
+template <>
+std::forward_list<FlagBase*> FlagBase::ALL_FLAGS;
+
+class FlagsTests;
+
+// This class defines a flag with a value of a particular type.
+template <typename Value>
+class Flag : public FlagBase {
+ public:
+ // Create a new Flag. The name parameter is used to generate the names from the various parameter
+ // sources. See the documentation on the Flags struct for an example.
+ explicit Flag(const std::string& name, Value default_value = {});
+ virtual ~Flag() {}
+
+
+ // Returns the flag value.
+ //
+ // The value is retrieved in the following oder:
+ // 1) server side (device config) property
+ // 2) system property
+ // 3) cmdline flag
+ // 4) default value
+ ALWAYS_INLINE Value GetValue() const {
+ return std::get<0>(GetValueLocation());
+ }
+
+ ALWAYS_INLINE Value operator()() const {
+ return GetValue();
+ }
+
+ // Returns the value and the location of that value for the given flag.
+ ALWAYS_INLINE std::pair<Value, std::string> GetValueLocation() const {
+ DCHECK(initialized_);
+ if (from_server_setting_.has_value()) {
+ return std::pair{from_server_setting_.value(), server_setting_name_};
+ }
+ if (from_system_property_.has_value()) {
+ return std::pair{from_system_property_.value(), system_property_name_};
+ }
+ if (from_command_line_.has_value()) {
+ return std::pair{from_command_line_.value(), command_line_argument_name_};
+ }
+ return std::pair{default_, "default_value"};
+ }
+
+ void Dump(std::ostream& oss) const override;
+
+ protected:
+ FlagValuePointer GetCmdLineLocation() override { return &from_command_line_; }
+
+
+ // Reload the server-configured value and system property values. In general this should not be
+ // used directly, but it can be used to support reloading the value without restarting the device.
+ void Reload() override;
+
+ private:
+ bool initialized_;
+ const Value default_;
+ std::optional<Value> from_command_line_;
+ std::optional<Value> from_system_property_;
+ std::optional<Value> from_server_setting_;
+
+ friend class FlagsTests;
+};
+
+// This struct contains the list of ART flags. Flags are parameterized by the type of value they
+// support (bool, int, string, etc.). In addition to field name, flags have a name for the parameter
+// as well.
+//
+// Example:
+//
+// Flag<int> WriteMetricsToLog{"my-feature-test.flag", 42};
+//
+// This creates a boolean flag that can be read through gFlags.WriteMetricsToLog(). The default
+// value is false. Note that the default value can be left unspecified, in which the value of the
+// type's default constructor will be used.
+//
+// The flag can be set through the following generated means:
+//
+// Command Line:
+//
+// -Xmy-feature-test-flag=1
+//
+// Server Side (Phenotype) Configuration:
+//
+// persist.device_config.runtime_native.my-feature-test.flag
+//
+// System Property:
+//
+// setprop dalvik.vm.metrics.my-feature-test.flag 2
+struct Flags {
+ // Flag used to test the infra.
+ // TODO: can be removed once we add real flags.
+ Flag<int> MyFeatureTestFlag{"my-feature-test.flag", /*default_value=*/ 42};
+};
+
+// This is the actual instance of all the flags.
+extern Flags gFlags;
+
+} // namespace art
+
+#pragma clang diagnostic pop // -Wconversion
+
+#endif // ART_LIBARTBASE_BASE_FLAGS_H_
diff --git a/libartbase/base/flags_test.cc b/libartbase/base/flags_test.cc
new file mode 100644
index 0000000000..cfbf2a9f1c
--- /dev/null
+++ b/libartbase/base/flags_test.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011 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 "base/flags.h"
+
+#include <optional>
+
+#include "android-base/properties.h"
+#include "common_runtime_test.h"
+
+
+namespace art {
+
+class FlagsTests : public CommonRuntimeTest {
+ protected:
+ void assertCmdlineValue(bool has_value, int expected) {
+ ASSERT_EQ(gFlags.MyFeatureTestFlag.from_command_line_.has_value(), has_value);
+ if (has_value) {
+ ASSERT_EQ(gFlags.MyFeatureTestFlag.from_command_line_.value(), expected);
+ }
+ }
+
+ void assertSysPropValue(bool has_value, int expected) {
+ ASSERT_EQ(gFlags.MyFeatureTestFlag.from_system_property_.has_value(), has_value);
+ if (has_value) {
+ ASSERT_EQ(gFlags.MyFeatureTestFlag.from_system_property_.value(), expected);
+ }
+ }
+
+ void assertServerSettingValue(bool has_value, int expected) {
+ ASSERT_EQ(gFlags.MyFeatureTestFlag.from_server_setting_.has_value(), has_value);
+ if (has_value) {
+ ASSERT_EQ(gFlags.MyFeatureTestFlag.from_server_setting_.value(), expected);
+ }
+ }
+
+ void assertDefaultValue(int expected) {
+ ASSERT_EQ(gFlags.MyFeatureTestFlag.default_, expected);
+ }
+};
+
+class FlagsTestsWithCmdLine : public FlagsTests {
+ public:
+ ~FlagsTestsWithCmdLine() {
+ android::base::SetProperty("dalvik.vm.my-feature-test.flag", "");
+ android::base::SetProperty("persist.device_config.runtime_native.my-feature-test.flag", "");
+ }
+
+ protected:
+ void SetUpRuntimeOptions(RuntimeOptions* options) override {
+ // Disable implicit dex2oat invocations when loading image spaces.
+ options->emplace_back("-Xmy-feature-test-flag:1", nullptr);
+ }
+};
+
+// Validate that when no flag is set, the default is taken and none of the other
+// locations are populated
+TEST_F(FlagsTests, ValidateDefaultValue) {
+ FlagBase::ReloadAllFlags("test");
+
+ assertCmdlineValue(false, 1);
+ assertSysPropValue(false, 2);
+ assertServerSettingValue(false, 3);
+ assertDefaultValue(42);
+
+ ASSERT_EQ(gFlags.MyFeatureTestFlag(), 42);
+}
+
+// Validate that the server side config is picked when it is set.
+TEST_F(FlagsTestsWithCmdLine, FlagsTestsGetValueServerSetting) {
+ android::base::SetProperty("dalvik.vm.my-feature-test.flag", "2");
+ android::base::SetProperty("persist.device_config.runtime_native.my-feature-test.flag", "3");
+
+ FlagBase::ReloadAllFlags("test");
+
+ assertCmdlineValue(true, 1);
+ assertSysPropValue(true, 2);
+ assertServerSettingValue(true, 3);
+ assertDefaultValue(42);
+
+ ASSERT_EQ(gFlags.MyFeatureTestFlag(), 3);
+}
+
+// Validate that the system property value is picked when the server one is not set.
+TEST_F(FlagsTestsWithCmdLine, FlagsTestsGetValueSysProperty) {
+ android::base::SetProperty("dalvik.vm.my-feature-test.flag", "2");
+
+ FlagBase::ReloadAllFlags("test");
+
+ assertCmdlineValue(true, 1);
+ assertSysPropValue(true, 2);
+ assertServerSettingValue(false, 3);
+ assertDefaultValue(42);
+
+ ASSERT_EQ(gFlags.MyFeatureTestFlag(), 2);
+}
+
+// Validate that the cmdline value is picked when no properties are set.
+TEST_F(FlagsTestsWithCmdLine, FlagsTestsGetValueCmdline) {
+ FlagBase::ReloadAllFlags("test");
+
+ assertCmdlineValue(true, 1);
+ assertSysPropValue(false, 2);
+ assertServerSettingValue(false, 3);
+ assertDefaultValue(42);
+
+ ASSERT_EQ(gFlags.MyFeatureTestFlag(), 1);
+}
+
+} // namespace art
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 9f75a88159..cdb63f31cb 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -269,6 +269,9 @@ static void ZygoteHooks_nativePostZygoteFork(JNIEnv*, jclass) {
static void ZygoteHooks_nativePostForkSystemServer(JNIEnv* env ATTRIBUTE_UNUSED,
jclass klass ATTRIBUTE_UNUSED,
jint runtime_flags) {
+ // Reload the current flags first. In case we need to take actions based on them.
+ Runtime::Current()->ReloadAllFlags(__FUNCTION__);
+
// Set the runtime state as the first thing, in case JIT and other services
// start querying it.
Runtime::Current()->SetAsSystemServer();
@@ -296,7 +299,9 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
jboolean is_zygote,
jstring instruction_set) {
DCHECK(!(is_system_server && is_zygote));
- // Set the runtime state as the first thing, in case JIT and other services
+ // Reload the current flags first. In case we need to take any updated actions.
+ Runtime::Current()->ReloadAllFlags(__FUNCTION__);
+ // Then, set the runtime state, in case JIT and other services
// start querying it.
Runtime::Current()->SetAsZygoteChild(is_system_server, is_zygote);
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 471a3fafd6..e5e7c4f9d0 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -23,6 +23,7 @@
#include <android-base/strings.h>
#include "base/file_utils.h"
+#include "base/flags.h"
#include "base/indenter.h"
#include "base/macros.h"
#include "base/utils.h"
@@ -464,8 +465,11 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.Define("-XX:PerfettoJavaHeapStackProf=_")
.WithType<bool>()
.WithValueMap({{"false", false}, {"true", true}})
- .IntoKey(M::PerfettoJavaHeapStackProf)
- .Ignore({
+ .IntoKey(M::PerfettoJavaHeapStackProf);
+
+ FlagBase::AddFlagsToCmdlineParser(parser_builder.get());
+
+ parser_builder->Ignore({
"-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
"-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
"-Xdexopt:_", "-Xnoquithandler", "-Xjnigreflimit:_", "-Xgenregmap", "-Xnogenregmap",
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 97c1d6dea7..52a4ab3ee5 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -56,6 +56,7 @@
#include "base/dumpable.h"
#include "base/enums.h"
#include "base/file_utils.h"
+#include "base/flags.h"
#include "base/malloc_arena_pool.h"
#include "base/mem_map_arena_pool.h"
#include "base/memory_tool.h"
@@ -1284,6 +1285,10 @@ void Runtime::InitializeApexVersions() {
apex_versions_ = result;
}
+void Runtime::ReloadAllFlags(const std::string& caller) {
+ FlagBase::ReloadAllFlags(caller);
+}
+
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
// (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
// Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc.
@@ -1294,6 +1299,9 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
ScopedTrace trace(__FUNCTION__);
CHECK_EQ(static_cast<size_t>(sysconf(_SC_PAGE_SIZE)), kPageSize);
+ // Reload all the flags value (from system properties and device configs).
+ ReloadAllFlags(__FUNCTION__);
+
// Early override for logging output.
if (runtime_options.Exists(Opt::UseStderrLogger)) {
android::base::SetLogger(android::base::StderrLogger);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 9664977577..1436a5f353 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -1005,6 +1005,17 @@ class Runtime {
return apex_versions_;
}
+ // Trigger a flag reload from system properties or device congfigs.
+ //
+ // Should only be called from runtime init and zygote post fork as
+ // we don't want to change the runtime config midway during execution.
+ //
+ // The caller argument should be the name of the function making this call
+ // and will be used to enforce the appropriate names.
+ //
+ // See Flags::ReloadAllFlags as well.
+ static void ReloadAllFlags(const std::string& caller);
+
private:
static void InitPlatformSignalHandlers();