Flutter Engine
switches.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <algorithm>
6 #include <iomanip>
7 #include <iostream>
8 #include <iterator>
9 #include <sstream>
10 #include <string>
11 
12 #include "flutter/fml/native_library.h"
13 #include "flutter/fml/paths.h"
14 #include "flutter/fml/size.h"
15 #include "flutter/shell/version/version.h"
16 
17 // Include once for the default enum definition.
18 #include "flutter/shell/common/switches.h"
19 
20 #undef SHELL_COMMON_SWITCHES_H_
21 
22 struct SwitchDesc {
23  flutter::Switch sw;
24  const std::string_view flag;
25  const char* help;
26 };
27 
28 #undef DEF_SWITCHES_START
29 #undef DEF_SWITCH
30 #undef DEF_SWITCHES_END
31 
32 // clang-format off
33 #define DEF_SWITCHES_START static const struct SwitchDesc gSwitchDescs[] = {
34 #define DEF_SWITCH(p_swtch, p_flag, p_help) \
35  { flutter::Switch:: p_swtch, p_flag, p_help },
36 #define DEF_SWITCHES_END };
37 // clang-format on
38 
39 // List of common and safe VM flags to allow to be passed directly to the VM.
40 #if FLUTTER_RELEASE
41 
42 // clang-format off
43 static const std::string gAllowedDartFlags[] = {
44  "--enable-isolate-groups",
45  "--no-enable-isolate-groups",
46  "--no-causal_async_stacks",
47  "--lazy_async_stacks",
48 };
49 // clang-format on
50 
51 #else
52 
53 // clang-format off
54 static const std::string gAllowedDartFlags[] = {
55  "--enable-isolate-groups",
56  "--no-enable-isolate-groups",
57  "--enable_mirrors",
58  "--enable-service-port-fallback",
59  "--lazy_async_stacks",
60  "--max_profile_depth",
61  "--no-causal_async_stacks",
62  "--profile_period",
63  "--random_seed",
64  "--sample-buffer-duration",
65  "--trace-reload",
66  "--trace-reload-verbose",
67  "--write-service-info",
68  "--null_assertions",
69 };
70 // clang-format on
71 
72 #endif // FLUTTER_RELEASE
73 
74 // Include again for struct definition.
75 #include "flutter/shell/common/switches.h"
76 
77 // Define symbols for the ICU data that is linked into the Flutter library on
78 // Android. This is a workaround for crashes seen when doing dynamic lookups
79 // of the engine's own symbols on some older versions of Android.
80 #if OS_ANDROID
81 extern uint8_t _binary_icudtl_dat_start[];
82 extern uint8_t _binary_icudtl_dat_end[];
83 
84 static std::unique_ptr<fml::Mapping> GetICUStaticMapping() {
85  return std::make_unique<fml::NonOwnedMapping>(
86  _binary_icudtl_dat_start,
87  _binary_icudtl_dat_end - _binary_icudtl_dat_start);
88 }
89 #endif
90 
91 namespace flutter {
92 
93 void PrintUsage(const std::string& executable_name) {
94  std::cerr << std::endl << " " << executable_name << std::endl << std::endl;
95 
96  std::cerr << "Versions: " << std::endl << std::endl;
97 
98  std::cerr << "Flutter Engine Version: " << GetFlutterEngineVersion()
99  << std::endl;
100  std::cerr << "Skia Version: " << GetSkiaVersion() << std::endl;
101 
102  std::cerr << "Dart Version: " << GetDartVersion() << std::endl << std::endl;
103 
104  std::cerr << "Available Flags:" << std::endl;
105 
106  const uint32_t column_width = 80;
107 
108  const uint32_t flags_count = static_cast<uint32_t>(Switch::Sentinel);
109 
110  uint32_t max_width = 2;
111  for (uint32_t i = 0; i < flags_count; i++) {
112  auto desc = gSwitchDescs[i];
113  max_width = std::max<uint32_t>(desc.flag.size() + 2, max_width);
114  }
115 
116  const uint32_t help_width = column_width - max_width - 3;
117 
118  std::cerr << std::string(column_width, '-') << std::endl;
119  for (uint32_t i = 0; i < flags_count; i++) {
120  auto desc = gSwitchDescs[i];
121 
122  std::cerr << std::setw(max_width)
123  << std::string("--") +
124  std::string{desc.flag.data(), desc.flag.size()}
125  << " : ";
126 
127  std::istringstream stream(desc.help);
128  int32_t remaining = help_width;
129 
130  std::string word;
131  while (stream >> word && remaining > 0) {
132  remaining -= (word.size() + 1);
133  if (remaining <= 0) {
134  std::cerr << std::endl
135  << std::string(max_width, ' ') << " " << word << " ";
136  remaining = help_width;
137  } else {
138  std::cerr << word << " ";
139  }
140  }
141 
142  std::cerr << std::endl;
143  }
144  std::cerr << std::string(column_width, '-') << std::endl;
145 }
146 
147 const std::string_view FlagForSwitch(Switch swtch) {
148  for (uint32_t i = 0; i < static_cast<uint32_t>(Switch::Sentinel); i++) {
149  if (gSwitchDescs[i].sw == swtch) {
150  return gSwitchDescs[i].flag;
151  }
152  }
153  return std::string_view();
154 }
155 
156 static bool IsAllowedDartVMFlag(const std::string& flag) {
157  for (uint32_t i = 0; i < fml::size(gAllowedDartFlags); ++i) {
158  const std::string& allowed = gAllowedDartFlags[i];
159  // Check that the prefix of the flag matches one of the allowed flags.
160  // We don't need to worry about cases like "--safe --sneaky_dangerous" as
161  // the VM will discard these as a single unrecognized flag.
162  if (std::equal(allowed.begin(), allowed.end(), flag.begin())) {
163  return true;
164  }
165  }
166  return false;
167 }
168 
169 template <typename T>
170 static bool GetSwitchValue(const fml::CommandLine& command_line,
171  Switch sw,
172  T* result) {
173  std::string switch_string;
174 
175  if (!command_line.GetOptionValue(FlagForSwitch(sw), &switch_string)) {
176  return false;
177  }
178 
179  std::stringstream stream(switch_string);
180  T value = 0;
181  if (stream >> value) {
182  *result = value;
183  return true;
184  }
185 
186  return false;
187 }
188 
189 std::unique_ptr<fml::Mapping> GetSymbolMapping(std::string symbol_prefix,
190  std::string native_lib_path) {
191  const uint8_t* mapping;
192  intptr_t size;
193 
194  auto lookup_symbol = [&mapping, &size, symbol_prefix](
195  const fml::RefPtr<fml::NativeLibrary>& library) {
196  mapping = library->ResolveSymbol((symbol_prefix + "_start").c_str());
197  size = reinterpret_cast<intptr_t>(
198  library->ResolveSymbol((symbol_prefix + "_size").c_str()));
199  };
200 
203  lookup_symbol(library);
204 
205  if (!(mapping && size)) {
206  // Symbol lookup for the current process fails on some devices. As a
207  // fallback, try doing the lookup based on the path to the Flutter library.
208  library = fml::NativeLibrary::Create(native_lib_path.c_str());
209  lookup_symbol(library);
210  }
211 
212  FML_CHECK(mapping && size) << "Unable to resolve symbols: " << symbol_prefix;
213  return std::make_unique<fml::NonOwnedMapping>(mapping, size);
214 }
215 
217  Settings settings = {};
218 
219  // Enable Observatory
220  settings.enable_observatory =
221  !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory));
222 
223  // Enable mDNS Observatory Publication
224  settings.enable_observatory_publication = !command_line.HasOption(
225  FlagForSwitch(Switch::DisableObservatoryPublication));
226 
227  // Set Observatory Host
228  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryHost))) {
229  command_line.GetOptionValue(FlagForSwitch(Switch::DeviceObservatoryHost),
230  &settings.observatory_host);
231  }
232  // Default the observatory port based on --ipv6 if not set.
233  if (settings.observatory_host.empty()) {
234  settings.observatory_host =
235  command_line.HasOption(FlagForSwitch(Switch::IPv6)) ? "::1"
236  : "127.0.0.1";
237  }
238 
239  // Set Observatory Port
240  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) {
241  if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort,
242  &settings.observatory_port)) {
243  FML_LOG(INFO)
244  << "Observatory port specified was malformed. Will default to "
245  << settings.observatory_port;
246  }
247  }
248 
249  settings.may_insecurely_connect_to_all_domains = !command_line.HasOption(
250  FlagForSwitch(Switch::DisallowInsecureConnections));
251 
252  command_line.GetOptionValue(FlagForSwitch(Switch::DomainNetworkPolicy),
253  &settings.domain_network_policy);
254 
255  // Disable need for authentication codes for VM service communication, if
256  // specified.
257  settings.disable_service_auth_codes =
258  command_line.HasOption(FlagForSwitch(Switch::DisableServiceAuthCodes));
259 
260  // Allow fallback to automatic port selection if binding to a specified port
261  // fails.
263  command_line.HasOption(FlagForSwitch(Switch::EnableServicePortFallback));
264 
265  // Checked mode overrides.
266  settings.disable_dart_asserts =
267  command_line.HasOption(FlagForSwitch(Switch::DisableDartAsserts));
268 
269  settings.start_paused =
270  command_line.HasOption(FlagForSwitch(Switch::StartPaused));
271 
272  settings.enable_checked_mode =
273  command_line.HasOption(FlagForSwitch(Switch::EnableCheckedMode));
274 
275  settings.enable_dart_profiling =
276  command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling));
277 
278  settings.enable_software_rendering =
279  command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering));
280 
281  settings.endless_trace_buffer =
282  command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer));
283 
284  settings.trace_startup =
285  command_line.HasOption(FlagForSwitch(Switch::TraceStartup));
286 
287  settings.trace_skia =
288  command_line.HasOption(FlagForSwitch(Switch::TraceSkia));
289 
290  command_line.GetOptionValue(FlagForSwitch(Switch::TraceAllowlist),
291  &settings.trace_allowlist);
292 
293  if (settings.trace_allowlist.empty()) {
294  command_line.GetOptionValue(FlagForSwitch(Switch::TraceWhitelist),
295  &settings.trace_allowlist);
296  if (!settings.trace_allowlist.empty()) {
297  FML_LOG(INFO)
298  << "--trace-whitelist is deprecated. Use --trace-allowlist instead.";
299  }
300  }
301 
302  settings.trace_systrace =
303  command_line.HasOption(FlagForSwitch(Switch::TraceSystrace));
304 
306  command_line.HasOption(FlagForSwitch(Switch::SkiaDeterministicRendering));
307 
308  settings.verbose_logging =
309  command_line.HasOption(FlagForSwitch(Switch::VerboseLogging));
310 
311  command_line.GetOptionValue(FlagForSwitch(Switch::FlutterAssetsDir),
312  &settings.assets_path);
313 
314  std::vector<std::string_view> aot_shared_library_name =
315  command_line.GetOptionValues(FlagForSwitch(Switch::AotSharedLibraryName));
316 
317  std::string snapshot_asset_path;
318  command_line.GetOptionValue(FlagForSwitch(Switch::SnapshotAssetPath),
319  &snapshot_asset_path);
320 
321  std::string vm_snapshot_data_filename;
323  &vm_snapshot_data_filename);
324 
325  std::string vm_snapshot_instr_filename;
327  &vm_snapshot_instr_filename);
328 
329  std::string isolate_snapshot_data_filename;
330  command_line.GetOptionValue(FlagForSwitch(Switch::IsolateSnapshotData),
331  &isolate_snapshot_data_filename);
332 
333  std::string isolate_snapshot_instr_filename;
334  command_line.GetOptionValue(
335  FlagForSwitch(Switch::IsolateSnapshotInstructions),
336  &isolate_snapshot_instr_filename);
337 
338  if (aot_shared_library_name.size() > 0) {
339  for (std::string_view name : aot_shared_library_name) {
340  settings.application_library_path.emplace_back(name);
341  }
342  } else if (snapshot_asset_path.size() > 0) {
343  settings.vm_snapshot_data_path =
344  fml::paths::JoinPaths({snapshot_asset_path, vm_snapshot_data_filename});
346  {snapshot_asset_path, vm_snapshot_instr_filename});
348  {snapshot_asset_path, isolate_snapshot_data_filename});
350  {snapshot_asset_path, isolate_snapshot_instr_filename});
351  }
352 
353  command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath),
354  &settings.temp_directory_path);
355 
356  if (settings.icu_initialization_required) {
357  command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath),
358  &settings.icu_data_path);
359  if (command_line.HasOption(FlagForSwitch(Switch::ICUSymbolPrefix))) {
360  std::string icu_symbol_prefix, native_lib_path;
361  command_line.GetOptionValue(FlagForSwitch(Switch::ICUSymbolPrefix),
362  &icu_symbol_prefix);
363  command_line.GetOptionValue(FlagForSwitch(Switch::ICUNativeLibPath),
364  &native_lib_path);
365 
366 #if OS_ANDROID
367  settings.icu_mapper = GetICUStaticMapping;
368 #else
369  settings.icu_mapper = [icu_symbol_prefix, native_lib_path] {
370  return GetSymbolMapping(icu_symbol_prefix, native_lib_path);
371  };
372 #endif
373  }
374  }
375 
376  settings.use_test_fonts =
377  command_line.HasOption(FlagForSwitch(Switch::UseTestFonts));
378 
379  std::string all_dart_flags;
380  if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags),
381  &all_dart_flags)) {
382  std::stringstream stream(all_dart_flags);
383  std::string flag;
384 
385  // Assume that individual flags are comma separated.
386  while (std::getline(stream, flag, ',')) {
387  if (!IsAllowedDartVMFlag(flag)) {
388  FML_LOG(FATAL) << "Encountered disallowed Dart VM flag: " << flag;
389  }
390  settings.dart_flags.push_back(flag);
391  }
392  }
393 
394 #if !FLUTTER_RELEASE
395  command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag);
396 #endif
397 
399  command_line.HasOption(FlagForSwitch(Switch::DumpSkpOnShaderCompilation));
400 
401  settings.cache_sksl =
402  command_line.HasOption(FlagForSwitch(Switch::CacheSkSL));
403 
404  settings.purge_persistent_cache =
405  command_line.HasOption(FlagForSwitch(Switch::PurgePersistentCache));
406 
407  return settings;
408 }
409 
410 } // namespace flutter
const char * GetFlutterEngineVersion()
Definition: version.cc:11
const char * GetDartVersion()
Definition: version.cc:19
bool enable_checked_mode
Definition: settings.h:101
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotData
Definition: switches.h:32
static fml::RefPtr< NativeLibrary > CreateForCurrentProcess()
bool skia_deterministic_rendering_on_cpu
Definition: settings.h:202
std::string trace_allowlist
Definition: settings.h:104
std::string temp_directory_path
Definition: settings.h:95
std::string isolate_snapshot_instr_path
Definition: settings.h:79
bool GetOptionValue(std::string_view name, std::string *value) const
Definition: command_line.cc:51
bool endless_trace_buffer
Definition: settings.h:110
uint32_t observatory_port
Definition: settings.h:142
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
Settings SettingsFromCommandLine(const fml::CommandLine &command_line)
Definition: switches.cc:216
#define FML_LOG(severity)
Definition: logging.h:65
static const std::string gAllowedDartFlags[]
Definition: switches.cc:54
const std::string_view FlagForSwitch(Switch swtch)
Definition: switches.cc:147
flutter::Switch sw
Definition: switches.cc:23
std::string isolate_snapshot_data_path
Definition: settings.h:77
bool verbose_logging
Definition: settings.h:203
const std::string_view flag
Definition: switches.cc:24
static bool GetSwitchValue(const fml::CommandLine &command_line, Switch sw, T *result)
Definition: switches.cc:170
std::string JoinPaths(std::initializer_list< std::string > components)
Definition: paths.cc:14
uint8_t value
static fml::RefPtr< NativeLibrary > Create(const char *path)
std::string domain_network_policy
Definition: settings.h:117
bool enable_dart_profiling
Definition: settings.h:111
bool enable_observatory_publication
Definition: settings.h:134
std::vector< std::string_view > GetOptionValues(std::string_view name) const
Definition: command_line.cc:61
std::string observatory_host
Definition: settings.h:137
std::vector< std::string > dart_flags
Definition: settings.h:96
bool dump_skp_on_shader_compilation
Definition: settings.h:107
void PrintUsage(const std::string &executable_name)
Definition: switches.cc:93
bool disable_service_auth_codes
Definition: settings.h:146
const char * GetSkiaVersion()
Definition: version.cc:15
static bool IsAllowedDartVMFlag(const std::string &flag)
Definition: switches.cc:156
std::string icu_data_path
Definition: settings.h:211
std::vector< std::string > application_library_path
Definition: settings.h:89
bool enable_observatory
Definition: settings.h:129
const char * name
Definition: fuchsia.cc:50
#define FML_CHECK(condition)
Definition: logging.h:68
bool disable_dart_asserts
Definition: settings.h:112
std::string vm_snapshot_data_path
Definition: settings.h:72
bool may_insecurely_connect_to_all_domains
Definition: settings.h:115
bool icu_initialization_required
Definition: settings.h:210
MappingCallback icu_mapper
Definition: settings.h:212
const char * help
Definition: switches.cc:25
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions
Definition: switches.h:32
std::unique_ptr< fml::Mapping > GetSymbolMapping(std::string symbol_prefix, std::string native_lib_path)
Definition: switches.cc:189
std::string vm_snapshot_instr_path
Definition: settings.h:74
std::string assets_path
Definition: settings.h:217
bool enable_software_rendering
Definition: settings.h:201
std::string log_tag
Definition: settings.h:204
bool purge_persistent_cache
Definition: settings.h:109
bool enable_service_port_fallback
Definition: settings.h:150
bool HasOption(std::string_view name, size_t *index=nullptr) const
Definition: command_line.cc:40