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  "--lazy_async_stacks",
47 };
48 // clang-format on
49 
50 #else
51 
52 // clang-format off
53 static const std::string gAllowedDartFlags[] = {
54  "--enable-isolate-groups",
55  "--no-enable-isolate-groups",
56  "--enable_mirrors",
57  "--enable-service-port-fallback",
58  "--lazy_async_stacks",
59  "--max_profile_depth",
60  "--profile_period",
61  "--random_seed",
62  "--sample-buffer-duration",
63  "--trace-kernel",
64  "--trace-reload",
65  "--trace-reload-verbose",
66  "--write-service-info",
67  "--null_assertions",
68  "--strict_null_safety_checks",
69  "--enable-display-list",
70  "--no-enable-display-list",
71 };
72 // clang-format on
73 
74 #endif // FLUTTER_RELEASE
75 
76 // Include again for struct definition.
77 #include "flutter/shell/common/switches.h"
78 
79 // Define symbols for the ICU data that is linked into the Flutter library on
80 // Android. This is a workaround for crashes seen when doing dynamic lookups
81 // of the engine's own symbols on some older versions of Android.
82 #if OS_ANDROID
83 extern uint8_t _binary_icudtl_dat_start[];
84 extern uint8_t _binary_icudtl_dat_end[];
85 
86 static std::unique_ptr<fml::Mapping> GetICUStaticMapping() {
87  return std::make_unique<fml::NonOwnedMapping>(
88  _binary_icudtl_dat_start,
89  _binary_icudtl_dat_end - _binary_icudtl_dat_start);
90 }
91 #endif
92 
93 namespace flutter {
94 
95 void PrintUsage(const std::string& executable_name) {
96  std::cerr << std::endl << " " << executable_name << std::endl << std::endl;
97 
98  std::cerr << "Versions: " << std::endl << std::endl;
99 
100  std::cerr << "Flutter Engine Version: " << GetFlutterEngineVersion()
101  << std::endl;
102  std::cerr << "Skia Version: " << GetSkiaVersion() << std::endl;
103 
104  std::cerr << "Dart Version: " << GetDartVersion() << std::endl << std::endl;
105 
106  std::cerr << "Available Flags:" << std::endl;
107 
108  const uint32_t column_width = 80;
109 
110  const uint32_t flags_count = static_cast<uint32_t>(Switch::Sentinel);
111 
112  uint32_t max_width = 2;
113  for (uint32_t i = 0; i < flags_count; i++) {
114  auto desc = gSwitchDescs[i];
115  max_width = std::max<uint32_t>(desc.flag.size() + 2, max_width);
116  }
117 
118  const uint32_t help_width = column_width - max_width - 3;
119 
120  std::cerr << std::string(column_width, '-') << std::endl;
121  for (uint32_t i = 0; i < flags_count; i++) {
122  auto desc = gSwitchDescs[i];
123 
124  std::cerr << std::setw(max_width)
125  << std::string("--") +
126  std::string{desc.flag.data(), desc.flag.size()}
127  << " : ";
128 
129  std::istringstream stream(desc.help);
130  int32_t remaining = help_width;
131 
132  std::string word;
133  while (stream >> word && remaining > 0) {
134  remaining -= (word.size() + 1);
135  if (remaining <= 0) {
136  std::cerr << std::endl
137  << std::string(max_width, ' ') << " " << word << " ";
138  remaining = help_width;
139  } else {
140  std::cerr << word << " ";
141  }
142  }
143 
144  std::cerr << std::endl;
145  }
146  std::cerr << std::string(column_width, '-') << std::endl;
147 }
148 
149 const std::string_view FlagForSwitch(Switch swtch) {
150  for (uint32_t i = 0; i < static_cast<uint32_t>(Switch::Sentinel); i++) {
151  if (gSwitchDescs[i].sw == swtch) {
152  return gSwitchDescs[i].flag;
153  }
154  }
155  return std::string_view();
156 }
157 
158 static std::vector<std::string> ParseCommaDelimited(const std::string& input) {
159  std::istringstream ss(input);
160  std::vector<std::string> result;
161  std::string token;
162  while (std::getline(ss, token, ',')) {
163  result.push_back(token);
164  }
165  return result;
166 }
167 
168 static bool IsAllowedDartVMFlag(const std::string& flag) {
169  for (uint32_t i = 0; i < fml::size(gAllowedDartFlags); ++i) {
170  const std::string& allowed = gAllowedDartFlags[i];
171  // Check that the prefix of the flag matches one of the allowed flags.
172  // We don't need to worry about cases like "--safe --sneaky_dangerous" as
173  // the VM will discard these as a single unrecognized flag.
174  if (std::equal(allowed.begin(), allowed.end(), flag.begin())) {
175  return true;
176  }
177  }
178  return false;
179 }
180 
181 template <typename T>
182 static bool GetSwitchValue(const fml::CommandLine& command_line,
183  Switch sw,
184  T* result) {
185  std::string switch_string;
186 
187  if (!command_line.GetOptionValue(FlagForSwitch(sw), &switch_string)) {
188  return false;
189  }
190 
191  std::stringstream stream(switch_string);
192  T value = 0;
193  if (stream >> value) {
194  *result = value;
195  return true;
196  }
197 
198  return false;
199 }
200 
201 std::unique_ptr<fml::Mapping> GetSymbolMapping(std::string symbol_prefix,
202  std::string native_lib_path) {
203  const uint8_t* mapping;
204  intptr_t size;
205 
206  auto lookup_symbol = [&mapping, &size, symbol_prefix](
207  const fml::RefPtr<fml::NativeLibrary>& library) {
208  mapping = library->ResolveSymbol((symbol_prefix + "_start").c_str());
209  size = reinterpret_cast<intptr_t>(
210  library->ResolveSymbol((symbol_prefix + "_size").c_str()));
211  };
212 
215  lookup_symbol(library);
216 
217  if (!(mapping && size)) {
218  // Symbol lookup for the current process fails on some devices. As a
219  // fallback, try doing the lookup based on the path to the Flutter library.
220  library = fml::NativeLibrary::Create(native_lib_path.c_str());
221  lookup_symbol(library);
222  }
223 
224  FML_CHECK(mapping && size) << "Unable to resolve symbols: " << symbol_prefix;
225  return std::make_unique<fml::NonOwnedMapping>(mapping, size);
226 }
227 
229  Settings settings = {};
230 
231  // Enable Observatory
232  settings.enable_observatory =
233  !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory));
234 
235  // Enable mDNS Observatory Publication
236  settings.enable_observatory_publication = !command_line.HasOption(
237  FlagForSwitch(Switch::DisableObservatoryPublication));
238 
239  // Set Observatory Host
240  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryHost))) {
241  command_line.GetOptionValue(FlagForSwitch(Switch::DeviceObservatoryHost),
242  &settings.observatory_host);
243  }
244  // Default the observatory port based on --ipv6 if not set.
245  if (settings.observatory_host.empty()) {
246  settings.observatory_host =
247  command_line.HasOption(FlagForSwitch(Switch::IPv6)) ? "::1"
248  : "127.0.0.1";
249  }
250 
251  // Set Observatory Port
252  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) {
253  if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort,
254  &settings.observatory_port)) {
255  FML_LOG(INFO)
256  << "Observatory port specified was malformed. Will default to "
257  << settings.observatory_port;
258  }
259  }
260 
261  settings.may_insecurely_connect_to_all_domains = !command_line.HasOption(
262  FlagForSwitch(Switch::DisallowInsecureConnections));
263 
264  command_line.GetOptionValue(FlagForSwitch(Switch::DomainNetworkPolicy),
265  &settings.domain_network_policy);
266 
267  // Disable need for authentication codes for VM service communication, if
268  // specified.
269  settings.disable_service_auth_codes =
270  command_line.HasOption(FlagForSwitch(Switch::DisableServiceAuthCodes));
271 
272  // Allow fallback to automatic port selection if binding to a specified port
273  // fails.
275  command_line.HasOption(FlagForSwitch(Switch::EnableServicePortFallback));
276 
277  // Checked mode overrides.
278  settings.disable_dart_asserts =
279  command_line.HasOption(FlagForSwitch(Switch::DisableDartAsserts));
280 
281  settings.start_paused =
282  command_line.HasOption(FlagForSwitch(Switch::StartPaused));
283 
284  settings.enable_checked_mode =
285  command_line.HasOption(FlagForSwitch(Switch::EnableCheckedMode));
286 
287  settings.enable_dart_profiling =
288  command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling));
289 
290  settings.enable_software_rendering =
291  command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering));
292 
293  settings.endless_trace_buffer =
294  command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer));
295 
296  settings.trace_startup =
297  command_line.HasOption(FlagForSwitch(Switch::TraceStartup));
298 
299 #if !FLUTTER_RELEASE
300  settings.trace_skia = true;
301 
302  if (command_line.HasOption(FlagForSwitch(Switch::TraceSkia))) {
303  // If --trace-skia is specified, then log all Skia events.
304  settings.trace_skia_allowlist.reset();
305  } else {
306  std::string trace_skia_allowlist;
307  command_line.GetOptionValue(FlagForSwitch(Switch::TraceSkiaAllowlist),
308  &trace_skia_allowlist);
309  if (trace_skia_allowlist.size()) {
310  settings.trace_skia_allowlist = ParseCommaDelimited(trace_skia_allowlist);
311  } else {
312  settings.trace_skia_allowlist = {"skia.shaders"};
313  }
314  }
315 #endif // !FLUTTER_RELEASE
316 
317  std::string trace_allowlist;
318  command_line.GetOptionValue(FlagForSwitch(Switch::TraceAllowlist),
319  &trace_allowlist);
320  settings.trace_allowlist = ParseCommaDelimited(trace_allowlist);
321 
322  settings.trace_systrace =
323  command_line.HasOption(FlagForSwitch(Switch::TraceSystrace));
324 
326  command_line.HasOption(FlagForSwitch(Switch::SkiaDeterministicRendering));
327 
328  settings.verbose_logging =
329  command_line.HasOption(FlagForSwitch(Switch::VerboseLogging));
330 
331  command_line.GetOptionValue(FlagForSwitch(Switch::FlutterAssetsDir),
332  &settings.assets_path);
333 
334  std::vector<std::string_view> aot_shared_library_name =
335  command_line.GetOptionValues(FlagForSwitch(Switch::AotSharedLibraryName));
336 
337  std::string snapshot_asset_path;
338  command_line.GetOptionValue(FlagForSwitch(Switch::SnapshotAssetPath),
339  &snapshot_asset_path);
340 
341  std::string vm_snapshot_data_filename;
343  &vm_snapshot_data_filename);
344 
345  std::string vm_snapshot_instr_filename;
347  &vm_snapshot_instr_filename);
348 
349  std::string isolate_snapshot_data_filename;
350  command_line.GetOptionValue(FlagForSwitch(Switch::IsolateSnapshotData),
351  &isolate_snapshot_data_filename);
352 
353  std::string isolate_snapshot_instr_filename;
354  command_line.GetOptionValue(
355  FlagForSwitch(Switch::IsolateSnapshotInstructions),
356  &isolate_snapshot_instr_filename);
357 
358  if (aot_shared_library_name.size() > 0) {
359  for (std::string_view name : aot_shared_library_name) {
360  settings.application_library_path.emplace_back(name);
361  }
362  } else if (snapshot_asset_path.size() > 0) {
363  settings.vm_snapshot_data_path =
364  fml::paths::JoinPaths({snapshot_asset_path, vm_snapshot_data_filename});
366  {snapshot_asset_path, vm_snapshot_instr_filename});
368  {snapshot_asset_path, isolate_snapshot_data_filename});
370  {snapshot_asset_path, isolate_snapshot_instr_filename});
371  }
372 
373  command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath),
374  &settings.temp_directory_path);
375 
376  if (settings.icu_initialization_required) {
377  command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath),
378  &settings.icu_data_path);
379  if (command_line.HasOption(FlagForSwitch(Switch::ICUSymbolPrefix))) {
380  std::string icu_symbol_prefix, native_lib_path;
381  command_line.GetOptionValue(FlagForSwitch(Switch::ICUSymbolPrefix),
382  &icu_symbol_prefix);
383  command_line.GetOptionValue(FlagForSwitch(Switch::ICUNativeLibPath),
384  &native_lib_path);
385 
386 #if OS_ANDROID
387  settings.icu_mapper = GetICUStaticMapping;
388 #else
389  settings.icu_mapper = [icu_symbol_prefix, native_lib_path] {
390  return GetSymbolMapping(icu_symbol_prefix, native_lib_path);
391  };
392 #endif
393  }
394  }
395 
396  settings.use_test_fonts =
397  command_line.HasOption(FlagForSwitch(Switch::UseTestFonts));
398 
399  settings.enable_skparagraph =
400  command_line.HasOption(FlagForSwitch(Switch::EnableSkParagraph));
401 
402  settings.prefetched_default_font_manager = command_line.HasOption(
403  FlagForSwitch(Switch::PrefetchedDefaultFontManager));
404 
405  std::string all_dart_flags;
406  if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags),
407  &all_dart_flags)) {
408  // Assume that individual flags are comma separated.
409  std::vector<std::string> flags = ParseCommaDelimited(all_dart_flags);
410  for (auto flag : flags) {
411  if (!IsAllowedDartVMFlag(flag)) {
412  FML_LOG(FATAL) << "Encountered disallowed Dart VM flag: " << flag;
413  }
414  settings.dart_flags.push_back(flag);
415  }
416  }
417  if (std::find(settings.dart_flags.begin(), settings.dart_flags.end(),
418  "--enable-display-list") != settings.dart_flags.end()) {
419  FML_LOG(ERROR) << "Manually enabling display lists";
420  settings.enable_display_list = true;
421  } else if (std::find(settings.dart_flags.begin(), settings.dart_flags.end(),
422  "--no-enable-display-list") !=
423  settings.dart_flags.end()) {
424  FML_LOG(ERROR) << "Manually disabling display lists";
425  settings.enable_display_list = false;
426  }
427 
428 #if !FLUTTER_RELEASE
429  command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag);
430 #endif
431 
433  command_line.HasOption(FlagForSwitch(Switch::DumpSkpOnShaderCompilation));
434 
435  settings.cache_sksl =
436  command_line.HasOption(FlagForSwitch(Switch::CacheSkSL));
437 
438  settings.purge_persistent_cache =
439  command_line.HasOption(FlagForSwitch(Switch::PurgePersistentCache));
440 
441  if (command_line.HasOption(FlagForSwitch(Switch::OldGenHeapSize))) {
442  std::string old_gen_heap_size;
443  command_line.GetOptionValue(FlagForSwitch(Switch::OldGenHeapSize),
444  &old_gen_heap_size);
445  settings.old_gen_heap_size = std::stoi(old_gen_heap_size);
446  }
447  return settings;
448 }
449 
450 } // namespace flutter
const char * GetFlutterEngineVersion()
Definition: version.cc:11
const char * GetDartVersion()
Definition: version.cc:19
bool enable_checked_mode
Definition: settings.h:129
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:249
bool enable_skparagraph
Definition: settings.h:189
std::string temp_directory_path
Definition: settings.h:123
std::string isolate_snapshot_instr_path
Definition: settings.h:107
bool GetOptionValue(std::string_view name, std::string *value) const
Definition: command_line.cc:51
bool endless_trace_buffer
Definition: settings.h:139
int64_t old_gen_heap_size
Definition: settings.h:283
uint32_t observatory_port
Definition: settings.h:171
static std::vector< std::string > ParseCommaDelimited(const std::string &input)
Definition: switches.cc:158
GAsyncResult * result
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
Settings SettingsFromCommandLine(const fml::CommandLine &command_line)
Definition: switches.cc:228
bool prefetched_default_font_manager
Definition: settings.h:186
#define FML_LOG(severity)
Definition: logging.h:65
static const std::string gAllowedDartFlags[]
Definition: switches.cc:53
const std::string_view FlagForSwitch(Switch swtch)
Definition: switches.cc:149
FlutterSemanticsFlag flags
flutter::Switch sw
Definition: switches.cc:23
std::string isolate_snapshot_data_path
Definition: settings.h:105
std::optional< std::vector< std::string > > trace_skia_allowlist
Definition: settings.h:133
bool verbose_logging
Definition: settings.h:250
const std::string_view flag
Definition: switches.cc:24
static bool GetSwitchValue(const fml::CommandLine &command_line, Switch sw, T *result)
Definition: switches.cc:182
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:146
bool enable_dart_profiling
Definition: settings.h:140
bool enable_observatory_publication
Definition: settings.h:163
bool enable_display_list
Definition: settings.h:192
std::vector< std::string_view > GetOptionValues(std::string_view name) const
Definition: command_line.cc:61
std::string observatory_host
Definition: settings.h:166
std::vector< std::string > dart_flags
Definition: settings.h:124
bool dump_skp_on_shader_compilation
Definition: settings.h:136
void PrintUsage(const std::string &executable_name)
Definition: switches.cc:95
bool disable_service_auth_codes
Definition: settings.h:175
const char * GetSkiaVersion()
Definition: version.cc:15
static bool IsAllowedDartVMFlag(const std::string &flag)
Definition: switches.cc:168
std::string icu_data_path
Definition: settings.h:258
std::vector< std::string > application_library_path
Definition: settings.h:117
bool enable_observatory
Definition: settings.h:158
const char * name
Definition: fuchsia.cc:50
#define FML_CHECK(condition)
Definition: logging.h:68
bool disable_dart_asserts
Definition: settings.h:141
std::string vm_snapshot_data_path
Definition: settings.h:100
bool may_insecurely_connect_to_all_domains
Definition: settings.h:144
bool icu_initialization_required
Definition: settings.h:257
MappingCallback icu_mapper
Definition: settings.h:259
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:201
std::string vm_snapshot_instr_path
Definition: settings.h:102
std::string assets_path
Definition: settings.h:264
bool enable_software_rendering
Definition: settings.h:248
std::string log_tag
Definition: settings.h:251
std::vector< std::string > trace_allowlist
Definition: settings.h:132
bool purge_persistent_cache
Definition: settings.h:138
bool enable_service_port_fallback
Definition: settings.h:179
bool HasOption(std::string_view name, size_t *index=nullptr) const
Definition: command_line.cc:40