File: flags.h

package info (click to toggle)
android-platform-art 14.0.0%2Br15-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 96,788 kB
  • sloc: cpp: 522,217; java: 194,312; asm: 28,950; python: 14,910; xml: 5,087; sh: 4,528; ansic: 4,035; makefile: 111; perl: 77
file content (323 lines) | stat: -rw-r--r-- 12,246 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*
 * 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 {

// Enum representing the type of the ART flag.
enum class FlagType {
  // A flag that only looks at the cmdline argument to retrieve its value.
  kCmdlineOnly,
  // A flag that also looks at system properties and device config
  // (phenotype properties) when retrieving its value.
  kDeviceConfig,
};

// 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,
               FlagType type) :
      command_line_argument_name_(command_line_argument_name),
      system_property_name_(system_property_name),
      server_setting_name_(server_setting_name),
      type_(type) {}
  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_;
  FlagType type_;
};

using FlagBase = FlagMetaBase<bool, int32_t, uint32_t, std::string>;

template <>
std::forward_list<FlagBase*> FlagBase::ALL_FLAGS;

class FlagsTests;

// Describes the possible origins of a flag value.
enum class FlagOrigin {
  kDefaultValue,
  kCmdlineArg,
  kSystemProperty,
  kServerSetting,
};

// 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.
  Flag(const std::string& name, Value default_value, FlagType type);
  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>(GetValueAndOrigin());
  }

  ALWAYS_INLINE Value operator()() const {
    return GetValue();
  }

  // Return the value of the flag as optional.
  //
  // Returns the value of the flag if and only if the flag is set via
  // a server side setting, system property or a cmdline arg.
  // Otherwise it returns nullopt (meaning this never returns the default value).
  //
  // This is useful for properties that do not have a good default natural value
  // (e.g. file path arguments).
  ALWAYS_INLINE std::optional<Value> GetValueOptional() const {
    std::pair<Value, FlagOrigin> result = GetValueAndOrigin();
    return std::get<1>(result) == FlagOrigin::kDefaultValue
      ? std::nullopt
      : std::make_optional(std::get<0>(result));
  }

  // Returns the value and the origin of that value for the given flag.
  ALWAYS_INLINE std::pair<Value, FlagOrigin> GetValueAndOrigin() const {
    DCHECK(initialized_);
    if (from_server_setting_.has_value()) {
      return std::pair{from_server_setting_.value(), FlagOrigin::kServerSetting};
    }
    if (from_system_property_.has_value()) {
      return std::pair{from_system_property_.value(), FlagOrigin::kSystemProperty};
    }
    if (from_command_line_.has_value()) {
      return std::pair{from_command_line_.value(), FlagOrigin::kCmdlineArg};
    }
    return std::pair{default_, FlagOrigin::kDefaultValue};
  }

  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 TestFlag;
};

// 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, FlagType::kDeviceConfig};
//
// This creates an integer flag that can be read through gFlags.WriteMetricsToLog(). The default
// value is 42. Note that the default value can be left unspecified, in which case 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<int32_t> MyFeatureTestFlag{"my-feature-test.flag", 42, FlagType::kDeviceConfig};


  // Metric infra flags.

  // The reporting spec for regular apps. An example of valid value is "S,1,2,4,*".
  // See metrics::ReportingPeriodSpec for complete docs.
  Flag<std::string> MetricsReportingSpec{
      "metrics.reporting-spec", "1,5,30,60,600", FlagType::kDeviceConfig};

  // The reporting spec for the system server. See MetricsReportingSpec as well.
  Flag<std::string> MetricsReportingSpecSystemServer{
      "metrics.reporting-spec-server", "1,10,60,3600,*", FlagType::kDeviceConfig};

  // The mods that should report metrics. Together with MetricsReportingNumMods, they
  // dictate what percentage of the runtime execution will report metrics.
  // If the `session_id (a random number) % MetricsReportingNumMods < MetricsReportingMods`
  // then the runtime session will report metrics.
  //
  // By default, the mods are 2, which means that 2 out of #{reporting-num-mods} of Android sessions
  // will be reported (with the default values this is 2/100 = 2%).
  Flag<uint32_t> MetricsReportingMods{"metrics.reporting-mods", 2, FlagType::kDeviceConfig};
  Flag<uint32_t> MetricsReportingModsServer{
      "metrics.reporting-mods-server", 2, FlagType::kDeviceConfig};

  // See MetricsReportingMods docs.
  //
  // By default the number of mods is 100, so MetricsReportingMods will naturally
  // read as the percent of runtime sessions that will report metrics. If a finer
  // grain unit is needed (e.g. a tenth of a percent), the num-mods can be increased.
  Flag<uint32_t> MetricsReportingNumMods{"metrics.reporting-num-mods", 100,
      FlagType::kDeviceConfig};
  Flag<uint32_t> MetricsReportingNumModsServer{"metrics.reporting-num-mods-server", 100,
      FlagType::kDeviceConfig};

  // Whether or not we should write metrics to statsd.
  // Note that the actual write is still controlled by
  // MetricsReportingMods and MetricsReportingNumMods.
  Flag<bool> MetricsWriteToStatsd{"metrics.write-to-statsd", true, FlagType::kDeviceConfig};

  // Whether or not we should write metrics to logcat.
  // Note that the actual write is still controlled by
  // MetricsReportingMods and MetricsReportingNumMods.
  Flag<bool> MetricsWriteToLogcat{ "metrics.write-to-logcat", false, FlagType::kCmdlineOnly};

  // Whether or not we should write metrics to a file.
  // Note that the actual write is still controlled by
  // MetricsReportingMods and MetricsReportingNumMods.
  Flag<std::string> MetricsWriteToFile{"metrics.write-to-file", "", FlagType::kCmdlineOnly};

  // The output format for metrics. This is only used
  // when writing metrics to a file; metrics written
  // to logcat will be in human-readable text format.
  // Supported values are "text" and "xml".
  Flag<std::string> MetricsFormat{"metrics.format", "text", FlagType::kCmdlineOnly};
};

// 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_