• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
44 namespace art {
45 
46 // Enum representing the type of the ART flag.
47 enum 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 
55 // 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.
58 template <typename... T>
59 class FlagMetaBase {
60  public:
FlagMetaBase(const std::string && command_line_argument_name,const std::string && system_property_name,const std::string && server_setting_name,FlagType type)61   FlagMetaBase(const std::string&& command_line_argument_name,
62                const std::string&& system_property_name,
63                const std::string&& server_setting_name,
64                FlagType type) :
65       command_line_argument_name_(command_line_argument_name),
66       system_property_name_(system_property_name),
67       server_setting_name_(server_setting_name),
68       type_(type) {}
~FlagMetaBase()69   virtual ~FlagMetaBase() {}
70 
71   template <typename Builder>
AddFlagsToCmdlineParser(Builder * 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.
ReloadAllFlags(const std::string & caller)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.
DumpFlags(std::ostream & oss)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_;
138   FlagType type_;
139 };
140 
141 using FlagBase = FlagMetaBase<bool, int32_t, uint32_t, std::string>;
142 
143 template <>
144 std::forward_list<FlagBase*> FlagBase::ALL_FLAGS;
145 
146 class FlagsTests;
147 
148 // Describes the possible origins of a flag value.
149 enum class FlagOrigin {
150   kDefaultValue,
151   kCmdlineArg,
152   kSystemProperty,
153   kServerSetting,
154 };
155 
156 // This class defines a flag with a value of a particular type.
157 template <typename Value>
158 class 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.
162   Flag(const std::string& name, Value default_value, FlagType type);
163   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
GetValue()173   ALWAYS_INLINE Value GetValue() const {
174     return std::get<0>(GetValueAndOrigin());
175   }
176 
operator()177   ALWAYS_INLINE Value operator()() const {
178     return GetValue();
179   }
180 
181   // 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).
GetValueOptional()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.
GetValueAndOrigin()197   ALWAYS_INLINE std::pair<Value, FlagOrigin> GetValueAndOrigin() const {
198     DCHECK(initialized_);
199     if (from_server_setting_.has_value()) {
200       return std::pair{from_server_setting_.value(), FlagOrigin::kServerSetting};
201     }
202     if (from_system_property_.has_value()) {
203       return std::pair{from_system_property_.value(), FlagOrigin::kSystemProperty};
204     }
205     if (from_command_line_.has_value()) {
206       return std::pair{from_command_line_.value(), FlagOrigin::kCmdlineArg};
207     }
208     return std::pair{default_, FlagOrigin::kDefaultValue};
209   }
210 
211   void Dump(std::ostream& oss) const override;
212 
213  protected:
GetCmdLineLocation()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 //
237 //     Flag<int> WriteMetricsToLog{"my-feature-test.flag", 42, FlagType::kDeviceConfig};
238 //
239 // 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
241 // 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
256 struct Flags {
257   // Flag used to test the infra.
258   // TODO: can be removed once we add real flags.
259   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.
266   Flag<std::string> MetricsReportingSpec{
267       "metrics.reporting-spec", "1,5,30,60,600", FlagType::kDeviceConfig};
268 
269   // The reporting spec for the system server. See MetricsReportingSpec as well.
270   Flag<std::string> MetricsReportingSpecSystemServer{
271       "metrics.reporting-spec-server", "1,10,60,3600,*", FlagType::kDeviceConfig};
272 
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   //
278   // 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};
283 
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};
291   Flag<uint32_t> MetricsReportingNumModsServer{"metrics.reporting-num-mods-server", 100,
292       FlagType::kDeviceConfig};
293 
294   // Whether or not we should write metrics to statsd.
295   // Note that the actual write is still controlled by
296   // MetricsReportingMods and MetricsReportingNumMods.
297   Flag<bool> MetricsWriteToStatsd{"metrics.write-to-statsd", true, FlagType::kDeviceConfig};
298 
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};
308 
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};
314 };
315 
316 // This is the actual instance of all the flags.
317 extern Flags gFlags;
318 
319 }  // namespace art
320 
321 #pragma clang diagnostic pop  // -Wconversion
322 
323 #endif  // ART_LIBARTBASE_BASE_FLAGS_H_
324