blob: 4734a60568a875f2e937068315210b6d32c549e2 [file] [log] [blame]
Martin Stjernholm9360b882021-06-15 21:47:54 +01001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_LIBARTBASE_BASE_FLAGS_H_
18#define ART_LIBARTBASE_BASE_FLAGS_H_
19
20#include <forward_list>
21#include <optional>
22#include <string>
23#include <variant>
24
25#include "logging.h"
26
27// This file defines a set of flags that can be used to enable/disable features within ART or
28// otherwise tune ART's behavior. Flags can be set through command line options, server side
29// configuration, system properties, or default values. This flexibility enables easier development
30// and also larger experiments.
31//
32// The value is retrieved in the following oder:
33// 1) server side (device config) property
34// 2) system property
35// 3) cmdline flag
36// 4) default value
37//
38// The flags are defined in the Flags struct near the bottom of the file. To define a new flag, add
39// a Flag field to the struct. Then to read the value of the flag, use gFlag.MyNewFlag().
40
41#pragma clang diagnostic push
42#pragma clang diagnostic error "-Wconversion"
43
44namespace art {
45
Martin Stjernholm663cc9e2021-06-29 02:34:06 +010046// Enum representing the type of the ART flag.
47enum class FlagType {
48 // A flag that only looks at the cmdline argument to retrieve its value.
49 kCmdlineOnly,
50 // A flag that also looks at system properties and device config
51 // (phenotype properties) when retrieving its value.
52 kDeviceConfig,
53};
54
Martin Stjernholm9360b882021-06-15 21:47:54 +010055// FlagMetaBase handles automatically adding flags to the command line parser. It is parameterized
56// by all supported flag types. In general, this should be treated as though it does not exist and
57// FlagBase, which is already specialized to the types we support, should be used instead.
58template <typename... T>
59class FlagMetaBase {
60 public:
61 FlagMetaBase(const std::string&& command_line_argument_name,
62 const std::string&& system_property_name,
Martin Stjernholm663cc9e2021-06-29 02:34:06 +010063 const std::string&& server_setting_name,
64 FlagType type) :
Martin Stjernholm9360b882021-06-15 21:47:54 +010065 command_line_argument_name_(command_line_argument_name),
66 system_property_name_(system_property_name),
Martin Stjernholm663cc9e2021-06-29 02:34:06 +010067 server_setting_name_(server_setting_name),
68 type_(type) {}
Martin Stjernholm9360b882021-06-15 21:47:54 +010069 virtual ~FlagMetaBase() {}
70
71 template <typename Builder>
72 static void AddFlagsToCmdlineParser(Builder* builder) {
73 for (auto* flag : ALL_FLAGS) {
74 // Each flag can return a pointer to where its command line value is stored. Because these can
75 // be different types, the return value comes as a variant. The cases list below contains a
76 // lambda that is specialized to handle each branch of the variant and call the correct
77 // methods on the command line parser builder.
78 FlagValuePointer location = flag->GetCmdLineLocation();
79 auto cases = {std::function<void()>([&]() {
80 if (std::holds_alternative<std::optional<T>*>(location)) {
81 builder = &builder->Define(flag->command_line_argument_name_.c_str())
82 .template WithType<T>()
83 .IntoLocation(std::get<std::optional<T>*>(location));
84 }
85 })...};
86 for (auto c : cases) {
87 c();
88 }
89 }
90 }
91
92 // Reload the value of the flags.
93 //
94 // DO NOT CALL this outside Runtime Init or Zygote post fork.
95 // This is a convention, as we should strive to have a constant view
96 // of the flags and not change the runtime behaviour midway during execution.
97 static void ReloadAllFlags(const std::string& caller) {
98 // Check the caller. This is a simple workaround to attract the attention
99 // to a possible dangerous call to ReloadAllFlags, while avoid building
100 // a lot of infra for it or having a complex friend definition.
101 DCHECK(caller == "Init"
102 || caller == "ZygoteHooks_nativePostForkChild"
103 || caller == "ZygoteHooks_nativePostForkSystemServer"
104 || caller == "test") << caller;
105 for (auto* flag : ALL_FLAGS) {
106 flag->Reload();
107 }
108
109 if (VLOG_IS_ON(startup)) {
110 VLOG_STREAM(startup) << "Dumping flags for " << caller;
111 DumpFlags(VLOG_STREAM(startup));
112 }
113 }
114
115 // Dump all the flags info to the given stream.
116 static void DumpFlags(std::ostream& oss) {
117 for (auto* flag : ALL_FLAGS) {
118 oss << "\n{\n";
119 flag->Dump(oss);
120 oss << "\n}";
121 }
122 }
123
124 protected:
125 using FlagValuePointer = std::variant<std::optional<T>*...>;
126 // Return the pointer to the value holder associated with the cmd line location.
127 virtual FlagValuePointer GetCmdLineLocation() = 0;
128 // Reloads the flag values.
129 virtual void Reload() = 0;
130 // Dumps the flags info to the given stream.
131 virtual void Dump(std::ostream& oss) const = 0;
132
133 static std::forward_list<FlagMetaBase<T...>*> ALL_FLAGS;
134
135 const std::string command_line_argument_name_;
136 const std::string system_property_name_;
137 const std::string server_setting_name_;
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100138 FlagType type_;
Martin Stjernholm9360b882021-06-15 21:47:54 +0100139};
140
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100141using FlagBase = FlagMetaBase<bool, int32_t, uint32_t, std::string>;
Martin Stjernholm9360b882021-06-15 21:47:54 +0100142
143template <>
144std::forward_list<FlagBase*> FlagBase::ALL_FLAGS;
145
146class FlagsTests;
147
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100148// Describes the possible origins of a flag value.
149enum class FlagOrigin {
150 kDefaultValue,
151 kCmdlineArg,
152 kSystemProperty,
153 kServerSetting,
154};
155
Martin Stjernholm9360b882021-06-15 21:47:54 +0100156// This class defines a flag with a value of a particular type.
157template <typename Value>
158class Flag : public FlagBase {
159 public:
160 // Create a new Flag. The name parameter is used to generate the names from the various parameter
161 // sources. See the documentation on the Flags struct for an example.
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100162 Flag(const std::string& name, Value default_value, FlagType type);
Martin Stjernholm9360b882021-06-15 21:47:54 +0100163 virtual ~Flag();
164
165
166 // Returns the flag value.
167 //
168 // The value is retrieved in the following oder:
169 // 1) server side (device config) property
170 // 2) system property
171 // 3) cmdline flag
172 // 4) default value
173 ALWAYS_INLINE Value GetValue() const {
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100174 return std::get<0>(GetValueAndOrigin());
Martin Stjernholm9360b882021-06-15 21:47:54 +0100175 }
176
177 ALWAYS_INLINE Value operator()() const {
178 return GetValue();
179 }
180
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100181 // Return the value of the flag as optional.
182 //
183 // Returns the value of the flag if and only if the flag is set via
184 // a server side setting, system property or a cmdline arg.
185 // Otherwise it returns nullopt (meaning this never returns the default value).
186 //
187 // This is useful for properties that do not have a good default natural value
188 // (e.g. file path arguments).
189 ALWAYS_INLINE std::optional<Value> GetValueOptional() const {
190 std::pair<Value, FlagOrigin> result = GetValueAndOrigin();
191 return std::get<1>(result) == FlagOrigin::kDefaultValue
192 ? std::nullopt
193 : std::make_optional(std::get<0>(result));
194 }
195
196 // Returns the value and the origin of that value for the given flag.
197 ALWAYS_INLINE std::pair<Value, FlagOrigin> GetValueAndOrigin() const {
Martin Stjernholm9360b882021-06-15 21:47:54 +0100198 DCHECK(initialized_);
199 if (from_server_setting_.has_value()) {
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100200 return std::pair{from_server_setting_.value(), FlagOrigin::kServerSetting};
Martin Stjernholm9360b882021-06-15 21:47:54 +0100201 }
202 if (from_system_property_.has_value()) {
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100203 return std::pair{from_system_property_.value(), FlagOrigin::kSystemProperty};
Martin Stjernholm9360b882021-06-15 21:47:54 +0100204 }
205 if (from_command_line_.has_value()) {
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100206 return std::pair{from_command_line_.value(), FlagOrigin::kCmdlineArg};
Martin Stjernholm9360b882021-06-15 21:47:54 +0100207 }
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100208 return std::pair{default_, FlagOrigin::kDefaultValue};
Martin Stjernholm9360b882021-06-15 21:47:54 +0100209 }
210
211 void Dump(std::ostream& oss) const override;
212
213 protected:
214 FlagValuePointer GetCmdLineLocation() override { return &from_command_line_; }
215
216
217 // Reload the server-configured value and system property values. In general this should not be
218 // used directly, but it can be used to support reloading the value without restarting the device.
219 void Reload() override;
220
221 private:
222 bool initialized_;
223 const Value default_;
224 std::optional<Value> from_command_line_;
225 std::optional<Value> from_system_property_;
226 std::optional<Value> from_server_setting_;
227
228 friend class TestFlag;
229};
230
231// This struct contains the list of ART flags. Flags are parameterized by the type of value they
232// support (bool, int, string, etc.). In addition to field name, flags have a name for the parameter
233// as well.
234//
235// Example:
236//
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100237// Flag<int> WriteMetricsToLog{"my-feature-test.flag", 42, FlagType::kDeviceConfig};
Martin Stjernholm9360b882021-06-15 21:47:54 +0100238//
Fairphone ODM25c12f52023-12-15 17:24:06 +0800239// This creates an integer flag that can be read through gFlags.WriteMetricsToLog(). The default
240// value is 42. Note that the default value can be left unspecified, in which case the value of the
Martin Stjernholm9360b882021-06-15 21:47:54 +0100241// type's default constructor will be used.
242//
243// The flag can be set through the following generated means:
244//
245// Command Line:
246//
247// -Xmy-feature-test-flag=1
248//
249// Server Side (Phenotype) Configuration:
250//
251// persist.device_config.runtime_native.my-feature-test.flag
252//
253// System Property:
254//
255// setprop dalvik.vm.metrics.my-feature-test.flag 2
256struct Flags {
257 // Flag used to test the infra.
258 // TODO: can be removed once we add real flags.
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100259 Flag<int32_t> MyFeatureTestFlag{"my-feature-test.flag", 42, FlagType::kDeviceConfig};
260
261
262 // Metric infra flags.
263
264 // The reporting spec for regular apps. An example of valid value is "S,1,2,4,*".
265 // See metrics::ReportingPeriodSpec for complete docs.
Fairphone ODM25c12f52023-12-15 17:24:06 +0800266 Flag<std::string> MetricsReportingSpec{
267 "metrics.reporting-spec", "1,5,30,60,600", FlagType::kDeviceConfig};
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100268
269 // The reporting spec for the system server. See MetricsReportingSpec as well.
Fairphone ODM25c12f52023-12-15 17:24:06 +0800270 Flag<std::string> MetricsReportingSpecSystemServer{
271 "metrics.reporting-spec-server", "1,10,60,3600,*", FlagType::kDeviceConfig};
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100272
273 // The mods that should report metrics. Together with MetricsReportingNumMods, they
274 // dictate what percentage of the runtime execution will report metrics.
275 // If the `session_id (a random number) % MetricsReportingNumMods < MetricsReportingMods`
276 // then the runtime session will report metrics.
277 //
Fairphone ODM25c12f52023-12-15 17:24:06 +0800278 // By default, the mods are 2, which means that 2 out of #{reporting-num-mods} of Android sessions
279 // will be reported (with the default values this is 2/100 = 2%).
280 Flag<uint32_t> MetricsReportingMods{"metrics.reporting-mods", 2, FlagType::kDeviceConfig};
281 Flag<uint32_t> MetricsReportingModsServer{
282 "metrics.reporting-mods-server", 2, FlagType::kDeviceConfig};
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100283
284 // See MetricsReportingMods docs.
285 //
286 // By default the number of mods is 100, so MetricsReportingMods will naturally
287 // read as the percent of runtime sessions that will report metrics. If a finer
288 // grain unit is needed (e.g. a tenth of a percent), the num-mods can be increased.
289 Flag<uint32_t> MetricsReportingNumMods{"metrics.reporting-num-mods", 100,
290 FlagType::kDeviceConfig};
Martin Stjernholm25f410c2021-07-05 01:07:38 +0100291 Flag<uint32_t> MetricsReportingNumModsServer{"metrics.reporting-num-mods-server", 100,
292 FlagType::kDeviceConfig};
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100293
294 // Whether or not we should write metrics to statsd.
295 // Note that the actual write is still controlled by
296 // MetricsReportingMods and MetricsReportingNumMods.
Fairphone ODM25c12f52023-12-15 17:24:06 +0800297 Flag<bool> MetricsWriteToStatsd{"metrics.write-to-statsd", true, FlagType::kDeviceConfig};
Martin Stjernholm663cc9e2021-06-29 02:34:06 +0100298
299 // Whether or not we should write metrics to logcat.
300 // Note that the actual write is still controlled by
301 // MetricsReportingMods and MetricsReportingNumMods.
302 Flag<bool> MetricsWriteToLogcat{ "metrics.write-to-logcat", false, FlagType::kCmdlineOnly};
303
304 // Whether or not we should write metrics to a file.
305 // Note that the actual write is still controlled by
306 // MetricsReportingMods and MetricsReportingNumMods.
307 Flag<std::string> MetricsWriteToFile{"metrics.write-to-file", "", FlagType::kCmdlineOnly};
Fairphone ODM25c12f52023-12-15 17:24:06 +0800308
309 // The output format for metrics. This is only used
310 // when writing metrics to a file; metrics written
311 // to logcat will be in human-readable text format.
312 // Supported values are "text" and "xml".
313 Flag<std::string> MetricsFormat{"metrics.format", "text", FlagType::kCmdlineOnly};
Martin Stjernholm9360b882021-06-15 21:47:54 +0100314};
315
316// This is the actual instance of all the flags.
317extern Flags gFlags;
318
319} // namespace art
320
321#pragma clang diagnostic pop // -Wconversion
322
323#endif // ART_LIBARTBASE_BASE_FLAGS_H_