• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
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 "base/trace_event/trace_config.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/notreached.h"
17 #include "base/strings/string_split.h"
18 #include "base/trace_event/memory_dump_manager.h"
19 #include "base/trace_event/memory_dump_request_args.h"
20 #include "base/trace_event/trace_event.h"
21 #include "third_party/abseil-cpp/absl/types/optional.h"
22 
23 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
24 #include "third_party/perfetto/protos/perfetto/config/track_event/track_event_config.gen.h"  // nogncheck
25 #endif
26 
27 namespace base::trace_event {
28 
29 namespace {
30 
31 // String options that can be used to initialize TraceOptions.
32 const char kRecordUntilFull[] = "record-until-full";
33 const char kRecordContinuously[] = "record-continuously";
34 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
35 const char kTraceToConsole[] = "trace-to-console";
36 const char kEnableSystrace[] = "enable-systrace";
37 constexpr int kEnableSystraceLength = sizeof(kEnableSystrace) - 1;
38 
39 const char kEnableArgumentFilter[] = "enable-argument-filter";
40 
41 // String parameters that can be used to parse the trace config string.
42 const char kRecordModeParam[] = "record_mode";
43 const char kTraceBufferSizeInEvents[] = "trace_buffer_size_in_events";
44 const char kTraceBufferSizeInKb[] = "trace_buffer_size_in_kb";
45 const char kEnableSystraceParam[] = "enable_systrace";
46 const char kSystraceEventsParam[] = "enable_systrace_events";
47 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
48 const char kEnableEventPackageNameFilterParam[] = "enable_package_name_filter";
49 
50 // String parameters that is used to parse memory dump config in trace config
51 // string.
52 const char kMemoryDumpConfigParam[] = "memory_dump_config";
53 const char kAllowedDumpModesParam[] = "allowed_dump_modes";
54 const char kTriggersParam[] = "triggers";
55 const char kTriggerModeParam[] = "mode";
56 const char kMinTimeBetweenDumps[] = "min_time_between_dumps_ms";
57 const char kTriggerTypeParam[] = "type";
58 const char kPeriodicIntervalLegacyParam[] = "periodic_interval_ms";
59 const char kHeapProfilerOptions[] = "heap_profiler_options";
60 const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
61 
62 // String parameters used to parse category event filters.
63 const char kEventFiltersParam[] = "event_filters";
64 const char kFilterPredicateParam[] = "filter_predicate";
65 const char kFilterArgsParam[] = "filter_args";
66 
67 // String parameter used to parse process filter.
68 const char kIncludedProcessesParam[] = "included_process_ids";
69 
70 const char kHistogramNamesParam[] = "histogram_names";
71 
72 class ConvertableTraceConfigToTraceFormat
73     : public base::trace_event::ConvertableToTraceFormat {
74  public:
ConvertableTraceConfigToTraceFormat(const TraceConfig & trace_config)75   explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
76       : trace_config_(trace_config) {}
77 
78   ~ConvertableTraceConfigToTraceFormat() override = default;
79 
AppendAsTraceFormat(std::string * out) const80   void AppendAsTraceFormat(std::string* out) const override {
81     out->append(trace_config_.ToString());
82   }
83 
84  private:
85   const TraceConfig trace_config_;
86 };
87 
GetDefaultAllowedMemoryDumpModes()88 std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
89   std::set<MemoryDumpLevelOfDetail> all_modes;
90   for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
91        mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
92     all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
93   }
94   return all_modes;
95 }
96 
97 }  // namespace
98 
HeapProfiler()99 TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
100     : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
101 
Clear()102 void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
103   breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
104 }
105 
ResetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig & memory_dump_config)106 void TraceConfig::ResetMemoryDumpConfig(
107     const TraceConfig::MemoryDumpConfig& memory_dump_config) {
108   memory_dump_config_.Clear();
109   memory_dump_config_ = memory_dump_config;
110 }
111 
112 TraceConfig::MemoryDumpConfig::MemoryDumpConfig() = default;
113 
114 TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
115     const MemoryDumpConfig& other) = default;
116 
117 TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() = default;
118 
Clear()119 void TraceConfig::MemoryDumpConfig::Clear() {
120   allowed_dump_modes.clear();
121   triggers.clear();
122   heap_profiler_options.Clear();
123 }
124 
Merge(const TraceConfig::MemoryDumpConfig & config)125 void TraceConfig::MemoryDumpConfig::Merge(
126     const TraceConfig::MemoryDumpConfig& config) {
127   triggers.insert(triggers.end(), config.triggers.begin(),
128                   config.triggers.end());
129   allowed_dump_modes.insert(config.allowed_dump_modes.begin(),
130                             config.allowed_dump_modes.end());
131   heap_profiler_options.breakdown_threshold_bytes =
132       std::min(heap_profiler_options.breakdown_threshold_bytes,
133                config.heap_profiler_options.breakdown_threshold_bytes);
134 }
135 
136 TraceConfig::ProcessFilterConfig::ProcessFilterConfig() = default;
137 
138 TraceConfig::ProcessFilterConfig::ProcessFilterConfig(
139     const ProcessFilterConfig& other) = default;
140 
ProcessFilterConfig(const std::unordered_set<base::ProcessId> & included_process_ids)141 TraceConfig::ProcessFilterConfig::ProcessFilterConfig(
142     const std::unordered_set<base::ProcessId>& included_process_ids)
143     : included_process_ids_(included_process_ids) {}
144 
145 TraceConfig::ProcessFilterConfig::~ProcessFilterConfig() = default;
146 
Clear()147 void TraceConfig::ProcessFilterConfig::Clear() {
148   included_process_ids_.clear();
149 }
150 
Merge(const ProcessFilterConfig & config)151 void TraceConfig::ProcessFilterConfig::Merge(
152     const ProcessFilterConfig& config) {
153   included_process_ids_.insert(config.included_process_ids_.begin(),
154                                config.included_process_ids_.end());
155 }
156 
InitializeFromConfigDict(const Value::Dict & dict)157 void TraceConfig::ProcessFilterConfig::InitializeFromConfigDict(
158     const Value::Dict& dict) {
159   included_process_ids_.clear();
160   const Value::List* value = dict.FindList(kIncludedProcessesParam);
161   if (!value)
162     return;
163   for (auto& pid_value : *value) {
164     if (pid_value.is_int()) {
165       included_process_ids_.insert(
166           static_cast<base::ProcessId>(pid_value.GetInt()));
167     }
168   }
169 }
170 
ToDict(Value::Dict & dict) const171 void TraceConfig::ProcessFilterConfig::ToDict(Value::Dict& dict) const {
172   if (included_process_ids_.empty())
173     return;
174   base::Value::List list;
175   std::set<base::ProcessId> ordered_set(included_process_ids_.begin(),
176                                         included_process_ids_.end());
177   for (auto process_id : ordered_set)
178     list.Append(static_cast<int>(process_id));
179   dict.Set(kIncludedProcessesParam, std::move(list));
180 }
181 
IsEnabled(base::ProcessId process_id) const182 bool TraceConfig::ProcessFilterConfig::IsEnabled(
183     base::ProcessId process_id) const {
184   return included_process_ids_.empty() ||
185          included_process_ids_.count(process_id);
186 }
187 
EventFilterConfig(const std::string & predicate_name)188 TraceConfig::EventFilterConfig::EventFilterConfig(
189     const std::string& predicate_name)
190     : predicate_name_(predicate_name) {}
191 
192 TraceConfig::EventFilterConfig::~EventFilterConfig() = default;
193 
EventFilterConfig(const EventFilterConfig & tc)194 TraceConfig::EventFilterConfig::EventFilterConfig(const EventFilterConfig& tc) {
195   *this = tc;
196 }
197 
operator =(const TraceConfig::EventFilterConfig & rhs)198 TraceConfig::EventFilterConfig& TraceConfig::EventFilterConfig::operator=(
199     const TraceConfig::EventFilterConfig& rhs) {
200   if (this == &rhs)
201     return *this;
202 
203   predicate_name_ = rhs.predicate_name_;
204   category_filter_ = rhs.category_filter_;
205 
206   args_ = rhs.args_.Clone();
207 
208   return *this;
209 }
210 
InitializeFromConfigDict(const Value::Dict & event_filter)211 void TraceConfig::EventFilterConfig::InitializeFromConfigDict(
212     const Value::Dict& event_filter) {
213   category_filter_.InitializeFromConfigDict(event_filter);
214 
215   const Value::Dict* args_dict = event_filter.FindDict(kFilterArgsParam);
216   if (args_dict)
217     args_ = args_dict->Clone();
218 }
219 
SetCategoryFilter(const TraceConfigCategoryFilter & category_filter)220 void TraceConfig::EventFilterConfig::SetCategoryFilter(
221     const TraceConfigCategoryFilter& category_filter) {
222   category_filter_ = category_filter;
223 }
224 
ToDict(Value::Dict & filter_dict) const225 void TraceConfig::EventFilterConfig::ToDict(Value::Dict& filter_dict) const {
226   filter_dict.Set(kFilterPredicateParam, predicate_name());
227 
228   category_filter_.ToDict(filter_dict);
229 
230   if (!args_.empty()) {
231     filter_dict.Set(kFilterArgsParam, args_.Clone());
232   }
233 }
234 
GetArgAsSet(const char * key,std::unordered_set<std::string> * out_set) const235 bool TraceConfig::EventFilterConfig::GetArgAsSet(
236     const char* key,
237     std::unordered_set<std::string>* out_set) const {
238   const Value::List* list = args_.FindList(key);
239   if (!list)
240     return false;
241   for (const Value& item : *list) {
242     if (item.is_string())
243       out_set->insert(item.GetString());
244   }
245   return true;
246 }
247 
IsCategoryGroupEnabled(const StringPiece & category_group_name) const248 bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
249     const StringPiece& category_group_name) const {
250   return category_filter_.IsCategoryGroupEnabled(category_group_name);
251 }
252 
253 // static
TraceRecordModeToStr(TraceRecordMode record_mode)254 std::string TraceConfig::TraceRecordModeToStr(TraceRecordMode record_mode) {
255   switch (record_mode) {
256     case RECORD_UNTIL_FULL:
257       return kRecordUntilFull;
258     case RECORD_CONTINUOUSLY:
259       return kRecordContinuously;
260     case RECORD_AS_MUCH_AS_POSSIBLE:
261       return kRecordAsMuchAsPossible;
262     case ECHO_TO_CONSOLE:
263       return kTraceToConsole;
264   }
265   return kRecordUntilFull;
266 }
267 
TraceConfig()268 TraceConfig::TraceConfig() {
269   InitializeDefault();
270 }
271 
TraceConfig(StringPiece category_filter_string,StringPiece trace_options_string)272 TraceConfig::TraceConfig(StringPiece category_filter_string,
273                          StringPiece trace_options_string) {
274   InitializeFromStrings(category_filter_string, trace_options_string);
275 }
276 
TraceConfig(StringPiece category_filter_string,TraceRecordMode record_mode)277 TraceConfig::TraceConfig(StringPiece category_filter_string,
278                          TraceRecordMode record_mode) {
279   InitializeFromStrings(category_filter_string,
280                         TraceConfig::TraceRecordModeToStr(record_mode));
281 }
282 
TraceConfig(const Value::Dict & config)283 TraceConfig::TraceConfig(const Value::Dict& config) {
284   InitializeFromConfigDict(config);
285 }
286 
TraceConfig(StringPiece config_string)287 TraceConfig::TraceConfig(StringPiece config_string) {
288   if (!config_string.empty())
289     InitializeFromConfigString(config_string);
290   else
291     InitializeDefault();
292 }
293 
294 TraceConfig::TraceConfig(const TraceConfig& tc) = default;
295 
296 TraceConfig::~TraceConfig() = default;
297 
operator =(const TraceConfig & rhs)298 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
299   if (this == &rhs)
300     return *this;
301 
302   record_mode_ = rhs.record_mode_;
303   trace_buffer_size_in_events_ = rhs.trace_buffer_size_in_events_;
304   trace_buffer_size_in_kb_ = rhs.trace_buffer_size_in_kb_;
305   enable_systrace_ = rhs.enable_systrace_;
306   enable_argument_filter_ = rhs.enable_argument_filter_;
307   category_filter_ = rhs.category_filter_;
308   process_filter_config_ = rhs.process_filter_config_;
309   enable_event_package_name_filter_ = rhs.enable_event_package_name_filter_;
310   memory_dump_config_ = rhs.memory_dump_config_;
311   event_filters_ = rhs.event_filters_;
312   histogram_names_ = rhs.histogram_names_;
313   systrace_events_ = rhs.systrace_events_;
314   return *this;
315 }
316 
ToString() const317 std::string TraceConfig::ToString() const {
318   Value dict = ToValue();
319   std::string json;
320   JSONWriter::Write(dict, &json);
321   return json;
322 }
323 
324 std::unique_ptr<ConvertableToTraceFormat>
AsConvertableToTraceFormat() const325 TraceConfig::AsConvertableToTraceFormat() const {
326   return std::make_unique<ConvertableTraceConfigToTraceFormat>(*this);
327 }
328 
ToCategoryFilterString() const329 std::string TraceConfig::ToCategoryFilterString() const {
330   return category_filter_.ToFilterString();
331 }
332 
IsCategoryGroupEnabled(const StringPiece & category_group_name) const333 bool TraceConfig::IsCategoryGroupEnabled(
334     const StringPiece& category_group_name) const {
335   // TraceLog should call this method only as part of enabling/disabling
336   // categories.
337   return category_filter_.IsCategoryGroupEnabled(category_group_name);
338 }
339 
Merge(const TraceConfig & config)340 void TraceConfig::Merge(const TraceConfig& config) {
341   if (record_mode_ != config.record_mode_ ||
342       enable_systrace_ != config.enable_systrace_ ||
343       enable_argument_filter_ != config.enable_argument_filter_ ||
344       enable_event_package_name_filter_ !=
345           config.enable_event_package_name_filter_) {
346     DLOG(ERROR) << "Attempting to merge trace config with a different "
347                 << "set of options.";
348   }
349   DCHECK_EQ(trace_buffer_size_in_events_, config.trace_buffer_size_in_events_)
350       << "Cannot change trace buffer size";
351 
352   category_filter_.Merge(config.category_filter_);
353   memory_dump_config_.Merge(config.memory_dump_config_);
354   process_filter_config_.Merge(config.process_filter_config_);
355 
356   event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
357                         config.event_filters().end());
358   histogram_names_.insert(config.histogram_names().begin(),
359                           config.histogram_names().end());
360 }
361 
Clear()362 void TraceConfig::Clear() {
363   record_mode_ = RECORD_UNTIL_FULL;
364   trace_buffer_size_in_events_ = 0;
365   trace_buffer_size_in_kb_ = 0;
366   enable_systrace_ = false;
367   enable_argument_filter_ = false;
368   enable_event_package_name_filter_ = false;
369   category_filter_.Clear();
370   memory_dump_config_.Clear();
371   process_filter_config_.Clear();
372   event_filters_.clear();
373   histogram_names_.clear();
374   systrace_events_.clear();
375 }
376 
InitializeDefault()377 void TraceConfig::InitializeDefault() {
378   record_mode_ = RECORD_UNTIL_FULL;
379   trace_buffer_size_in_events_ = 0;
380   trace_buffer_size_in_kb_ = 0;
381   enable_systrace_ = false;
382   enable_argument_filter_ = false;
383   enable_event_package_name_filter_ = false;
384 }
385 
InitializeFromConfigDict(const Value::Dict & dict)386 void TraceConfig::InitializeFromConfigDict(const Value::Dict& dict) {
387   record_mode_ = RECORD_UNTIL_FULL;
388   const std::string* record_mode = dict.FindString(kRecordModeParam);
389   if (record_mode) {
390     if (*record_mode == kRecordUntilFull) {
391       record_mode_ = RECORD_UNTIL_FULL;
392     } else if (*record_mode == kRecordContinuously) {
393       record_mode_ = RECORD_CONTINUOUSLY;
394     } else if (*record_mode == kTraceToConsole) {
395       record_mode_ = ECHO_TO_CONSOLE;
396     } else if (*record_mode == kRecordAsMuchAsPossible) {
397       record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
398     }
399   }
400   trace_buffer_size_in_events_ = base::saturated_cast<size_t>(
401       dict.FindInt(kTraceBufferSizeInEvents).value_or(0));
402   trace_buffer_size_in_kb_ = base::saturated_cast<size_t>(
403       dict.FindInt(kTraceBufferSizeInKb).value_or(0));
404 
405   enable_systrace_ = dict.FindBool(kEnableSystraceParam).value_or(false);
406   enable_argument_filter_ =
407       dict.FindBool(kEnableArgumentFilterParam).value_or(false);
408   enable_event_package_name_filter_ =
409       dict.FindBool(kEnableEventPackageNameFilterParam).value_or(false);
410 
411   category_filter_.InitializeFromConfigDict(dict);
412   process_filter_config_.InitializeFromConfigDict(dict);
413 
414   const Value::List* category_event_filters = dict.FindList(kEventFiltersParam);
415   if (category_event_filters)
416     SetEventFiltersFromConfigList(*category_event_filters);
417   const Value::List* histogram_names = dict.FindList(kHistogramNamesParam);
418   if (histogram_names)
419     SetHistogramNamesFromConfigList(*histogram_names);
420 
421   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
422     // If dump triggers not set, the client is using the legacy with just
423     // category enabled. So, use the default periodic dump config.
424     const Value::Dict* memory_dump_config =
425         dict.FindDict(kMemoryDumpConfigParam);
426     if (memory_dump_config)
427       SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
428     else
429       SetDefaultMemoryDumpConfig();
430   }
431 
432   systrace_events_.clear();
433   if (enable_systrace_) {
434     const Value::List* systrace_events = dict.FindList(kSystraceEventsParam);
435     if (systrace_events) {
436       for (const Value& value : *systrace_events) {
437         systrace_events_.insert(value.GetString());
438       }
439     }
440   }
441 }
442 
InitializeFromConfigString(StringPiece config_string)443 void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
444   absl::optional<Value> dict = JSONReader::Read(config_string);
445   if (dict && dict->is_dict())
446     InitializeFromConfigDict(dict->GetDict());
447   else
448     InitializeDefault();
449 }
450 
InitializeFromStrings(StringPiece category_filter_string,StringPiece trace_options_string)451 void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
452                                         StringPiece trace_options_string) {
453   if (!category_filter_string.empty())
454     category_filter_.InitializeFromString(category_filter_string);
455 
456   record_mode_ = RECORD_UNTIL_FULL;
457   trace_buffer_size_in_events_ = 0;
458   trace_buffer_size_in_kb_ = 0;
459   enable_systrace_ = false;
460   systrace_events_.clear();
461   enable_argument_filter_ = false;
462   enable_event_package_name_filter_ = false;
463   if (!trace_options_string.empty()) {
464     std::vector<std::string> split =
465         SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
466     for (const std::string& token : split) {
467       if (token == kRecordUntilFull) {
468         record_mode_ = RECORD_UNTIL_FULL;
469       } else if (token == kRecordContinuously) {
470         record_mode_ = RECORD_CONTINUOUSLY;
471       } else if (token == kTraceToConsole) {
472         record_mode_ = ECHO_TO_CONSOLE;
473       } else if (token == kRecordAsMuchAsPossible) {
474         record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
475       } else if (token.find(kEnableSystrace) == 0) {
476         // Find optional events list.
477         const size_t length = token.length();
478         if (length == kEnableSystraceLength) {
479           // Use all predefined categories.
480           enable_systrace_ = true;
481           continue;
482         }
483         const auto system_events_not_trimmed =
484             token.substr(kEnableSystraceLength);
485         const auto system_events =
486             TrimString(system_events_not_trimmed, kWhitespaceASCII, TRIM_ALL);
487         if (system_events[0] != '=') {
488           LOG(ERROR) << "Failed to parse " << token;
489           continue;
490         }
491         enable_systrace_ = true;
492         const std::vector<std::string> split_systrace_events = SplitString(
493             system_events.substr(1), " ", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
494         for (const std::string& systrace_event : split_systrace_events)
495           systrace_events_.insert(systrace_event);
496       } else if (token == kEnableArgumentFilter) {
497         enable_argument_filter_ = true;
498       }
499     }
500   }
501 
502   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
503     SetDefaultMemoryDumpConfig();
504   }
505 }
506 
SetMemoryDumpConfigFromConfigDict(const Value::Dict & memory_dump_config)507 void TraceConfig::SetMemoryDumpConfigFromConfigDict(
508     const Value::Dict& memory_dump_config) {
509   // Set allowed dump modes.
510   memory_dump_config_.allowed_dump_modes.clear();
511   const Value::List* allowed_modes_list =
512       memory_dump_config.FindList(kAllowedDumpModesParam);
513   if (allowed_modes_list) {
514     for (const Value& item : *allowed_modes_list) {
515       DCHECK(item.is_string());
516       memory_dump_config_.allowed_dump_modes.insert(
517           StringToMemoryDumpLevelOfDetail(item.GetString()));
518     }
519   } else {
520     // If allowed modes param is not given then allow all modes by default.
521     memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
522   }
523 
524   // Set triggers
525   memory_dump_config_.triggers.clear();
526   const Value::List* trigger_list = memory_dump_config.FindList(kTriggersParam);
527   if (trigger_list) {
528     for (const Value& trigger : *trigger_list) {
529       if (!trigger.is_dict()) {
530         continue;
531       }
532       const Value::Dict& trigger_dict = trigger.GetDict();
533 
534       MemoryDumpConfig::Trigger dump_config;
535       absl::optional<int> interval = trigger_dict.FindInt(kMinTimeBetweenDumps);
536       if (!interval) {
537         // If "min_time_between_dumps_ms" param was not given, then the trace
538         // config uses old format where only periodic dumps are supported.
539         interval = trigger_dict.FindInt(kPeriodicIntervalLegacyParam);
540         dump_config.trigger_type = MemoryDumpType::PERIODIC_INTERVAL;
541       } else {
542         const std::string* trigger_type_str =
543             trigger_dict.FindString(kTriggerTypeParam);
544         DCHECK(trigger_type_str);
545         dump_config.trigger_type = StringToMemoryDumpType(*trigger_type_str);
546       }
547       DCHECK(interval.has_value());
548       DCHECK_GT(*interval, 0);
549       dump_config.min_time_between_dumps_ms = static_cast<uint32_t>(*interval);
550 
551       const std::string* level_of_detail_str =
552           trigger_dict.FindString(kTriggerModeParam);
553       DCHECK(level_of_detail_str);
554       dump_config.level_of_detail =
555           StringToMemoryDumpLevelOfDetail(*level_of_detail_str);
556 
557       memory_dump_config_.triggers.push_back(dump_config);
558     }
559   }
560 
561   // Set heap profiler options.
562   const Value::Dict* heap_profiler_options =
563       memory_dump_config.FindDict(kHeapProfilerOptions);
564   if (heap_profiler_options) {
565     absl::optional<int> min_size_bytes =
566         heap_profiler_options->FindInt(kBreakdownThresholdBytes);
567     if (min_size_bytes && *min_size_bytes >= 0) {
568       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
569           static_cast<uint32_t>(*min_size_bytes);
570     } else {
571       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
572           MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
573     }
574   }
575 }
576 
SetDefaultMemoryDumpConfig()577 void TraceConfig::SetDefaultMemoryDumpConfig() {
578   memory_dump_config_.Clear();
579   memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
580 }
581 
SetProcessFilterConfig(const ProcessFilterConfig & config)582 void TraceConfig::SetProcessFilterConfig(const ProcessFilterConfig& config) {
583   process_filter_config_ = config;
584 }
585 
SetHistogramNamesFromConfigList(const Value::List & histogram_names)586 void TraceConfig::SetHistogramNamesFromConfigList(
587     const Value::List& histogram_names) {
588   histogram_names_.clear();
589   for (const Value& value : histogram_names) {
590     histogram_names_.insert(value.GetString());
591   }
592 }
593 
SetEventFiltersFromConfigList(const Value::List & category_event_filters)594 void TraceConfig::SetEventFiltersFromConfigList(
595     const Value::List& category_event_filters) {
596   event_filters_.clear();
597 
598   for (const Value& event_filter : category_event_filters) {
599     if (!event_filter.is_dict()) {
600       continue;
601     }
602     const Value::Dict& event_filter_dict = event_filter.GetDict();
603 
604     const std::string* predicate_name =
605         event_filter_dict.FindString(kFilterPredicateParam);
606     CHECK(predicate_name) << "Invalid predicate name in category event filter.";
607 
608     EventFilterConfig new_config(*predicate_name);
609     new_config.InitializeFromConfigDict(event_filter_dict);
610     event_filters_.push_back(new_config);
611   }
612 }
613 
ToValue() const614 Value TraceConfig::ToValue() const {
615   Value::Dict dict;
616   dict.Set(kRecordModeParam, TraceConfig::TraceRecordModeToStr(record_mode_));
617   dict.Set(kEnableSystraceParam, enable_systrace_);
618   dict.Set(kEnableArgumentFilterParam, enable_argument_filter_);
619   if (trace_buffer_size_in_events_ > 0) {
620     dict.Set(kTraceBufferSizeInEvents,
621              base::checked_cast<int>(trace_buffer_size_in_events_));
622   }
623   if (trace_buffer_size_in_kb_ > 0) {
624     dict.Set(kTraceBufferSizeInKb,
625              base::checked_cast<int>(trace_buffer_size_in_kb_));
626   }
627 
628   dict.Set(kEnableEventPackageNameFilterParam,
629            enable_event_package_name_filter_);
630 
631   category_filter_.ToDict(dict);
632   process_filter_config_.ToDict(dict);
633 
634   if (!event_filters_.empty()) {
635     Value::List filter_list;
636     for (const EventFilterConfig& filter : event_filters_) {
637       Value::Dict filter_dict;
638       filter.ToDict(filter_dict);
639       filter_list.Append(std::move(filter_dict));
640     }
641     dict.Set(kEventFiltersParam, std::move(filter_list));
642   }
643 
644   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
645     Value::List allowed_modes;
646     for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
647       allowed_modes.Append(MemoryDumpLevelOfDetailToString(dump_mode));
648 
649     Value::Dict memory_dump_config;
650     memory_dump_config.Set(kAllowedDumpModesParam, std::move(allowed_modes));
651 
652     Value::List triggers_list;
653     for (const auto& config : memory_dump_config_.triggers) {
654       Value::Dict trigger_dict;
655 
656       trigger_dict.Set(kTriggerTypeParam,
657                        MemoryDumpTypeToString(config.trigger_type));
658       trigger_dict.Set(kMinTimeBetweenDumps,
659                        static_cast<int>(config.min_time_between_dumps_ms));
660       trigger_dict.Set(kTriggerModeParam,
661                        MemoryDumpLevelOfDetailToString(config.level_of_detail));
662       triggers_list.Append(std::move(trigger_dict));
663     }
664 
665     // Empty triggers will still be specified explicitly since it means that
666     // the periodic dumps are not enabled.
667     memory_dump_config.Set(kTriggersParam, std::move(triggers_list));
668 
669     if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
670         MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
671       Value::Dict options;
672       options.Set(
673           kBreakdownThresholdBytes,
674           base::checked_cast<int>(memory_dump_config_.heap_profiler_options
675                                       .breakdown_threshold_bytes));
676       memory_dump_config.Set(kHeapProfilerOptions, std::move(options));
677     }
678     dict.Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
679   }
680 
681   if (!histogram_names_.empty()) {
682     base::Value::List histogram_names;
683     for (const std::string& histogram_name : histogram_names_)
684       histogram_names.Append(histogram_name);
685     dict.Set(kHistogramNamesParam, std::move(histogram_names));
686   }
687 
688   if (enable_systrace_) {
689     if (!systrace_events_.empty()) {
690       base::Value::List systrace_events;
691       for (const std::string& systrace_event : systrace_events_)
692         systrace_events.Append(systrace_event);
693       dict.Set(kSystraceEventsParam, std::move(systrace_events));
694     }
695   }
696 
697   return Value(std::move(dict));
698 }
699 
EnableSystraceEvent(const std::string & systrace_event)700 void TraceConfig::EnableSystraceEvent(const std::string& systrace_event) {
701   systrace_events_.insert(systrace_event);
702 }
703 
EnableHistogram(const std::string & histogram_name)704 void TraceConfig::EnableHistogram(const std::string& histogram_name) {
705   histogram_names_.insert(histogram_name);
706 }
707 
ToTraceOptionsString() const708 std::string TraceConfig::ToTraceOptionsString() const {
709   std::string ret;
710   switch (record_mode_) {
711     case RECORD_UNTIL_FULL:
712       ret = kRecordUntilFull;
713       break;
714     case RECORD_CONTINUOUSLY:
715       ret = kRecordContinuously;
716       break;
717     case RECORD_AS_MUCH_AS_POSSIBLE:
718       ret = kRecordAsMuchAsPossible;
719       break;
720     case ECHO_TO_CONSOLE:
721       ret = kTraceToConsole;
722       break;
723   }
724   if (enable_systrace_) {
725     ret += ",";
726     ret += kEnableSystrace;
727     bool first_param = true;
728     for (const std::string& systrace_event : systrace_events_) {
729       if (first_param) {
730         ret += "=";
731         first_param = false;
732       } else {
733         ret += " ";
734       }
735       ret = ret + systrace_event;
736     }
737   }
738   if (enable_argument_filter_) {
739     ret += ",";
740     ret += kEnableArgumentFilter;
741   }
742   return ret;
743 }
744 
745 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
ToPerfettoTrackEventConfigRaw(bool privacy_filtering_enabled) const746 std::string TraceConfig::ToPerfettoTrackEventConfigRaw(
747     bool privacy_filtering_enabled) const {
748   perfetto::protos::gen::TrackEventConfig te_cfg;
749   // If no categories are explicitly enabled, enable the default ones.
750   // Otherwise only matching categories are enabled.
751   if (!category_filter_.included_categories().empty())
752     te_cfg.add_disabled_categories("*");
753   // Metadata is always enabled.
754   te_cfg.add_enabled_categories("__metadata");
755   for (const auto& excluded : category_filter_.excluded_categories()) {
756     te_cfg.add_disabled_categories(excluded);
757   }
758   for (const auto& included : category_filter_.included_categories()) {
759     te_cfg.add_enabled_categories(included);
760   }
761   for (const auto& disabled : category_filter_.disabled_categories()) {
762     te_cfg.add_enabled_categories(disabled);
763   }
764   te_cfg.set_enable_thread_time_sampling(true);
765   te_cfg.set_timestamp_unit_multiplier(1000);
766   if (privacy_filtering_enabled) {
767     te_cfg.set_filter_dynamic_event_names(true);
768     te_cfg.set_filter_debug_annotations(true);
769   }
770   return te_cfg.SerializeAsString();
771 }
772 #endif
773 
774 }  // namespace base::trace_event
775