• 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 <optional>
11 #include <string_view>
12 #include <utility>
13 
14 #include "base/containers/contains.h"
15 #include "base/json/json_reader.h"
16 #include "base/json/json_writer.h"
17 #include "base/logging.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/notreached.h"
20 #include "base/strings/string_split.h"
21 #include "base/trace_event/memory_dump_manager.h"
22 #include "base/trace_event/memory_dump_request_args.h"
23 #include "base/trace_event/trace_event.h"
24 
25 #include "third_party/perfetto/protos/perfetto/config/track_event/track_event_config.gen.h"  // nogncheck
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::kFirst);
91        mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::kLast); 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 
IsEquivalentTo(const EventFilterConfig & other) const211 bool TraceConfig::EventFilterConfig::IsEquivalentTo(
212     const EventFilterConfig& other) const {
213   return predicate_name_ == other.predicate_name_ &&
214          category_filter_.IsEquivalentTo(category_filter_) &&
215          args_ == other.args_;
216 }
217 
InitializeFromConfigDict(const Value::Dict & event_filter)218 void TraceConfig::EventFilterConfig::InitializeFromConfigDict(
219     const Value::Dict& event_filter) {
220   category_filter_.InitializeFromConfigDict(event_filter);
221 
222   const Value::Dict* args_dict = event_filter.FindDict(kFilterArgsParam);
223   if (args_dict)
224     args_ = args_dict->Clone();
225 }
226 
SetCategoryFilter(const TraceConfigCategoryFilter & category_filter)227 void TraceConfig::EventFilterConfig::SetCategoryFilter(
228     const TraceConfigCategoryFilter& category_filter) {
229   category_filter_ = category_filter;
230 }
231 
ToDict(Value::Dict & filter_dict) const232 void TraceConfig::EventFilterConfig::ToDict(Value::Dict& filter_dict) const {
233   filter_dict.Set(kFilterPredicateParam, predicate_name());
234 
235   category_filter_.ToDict(filter_dict);
236 
237   if (!args_.empty()) {
238     filter_dict.Set(kFilterArgsParam, args_.Clone());
239   }
240 }
241 
GetArgAsSet(const char * key,std::unordered_set<std::string> * out_set) const242 bool TraceConfig::EventFilterConfig::GetArgAsSet(
243     const char* key,
244     std::unordered_set<std::string>* out_set) const {
245   const Value::List* list = args_.FindList(key);
246   if (!list)
247     return false;
248   for (const Value& item : *list) {
249     if (item.is_string())
250       out_set->insert(item.GetString());
251   }
252   return true;
253 }
254 
IsCategoryGroupEnabled(std::string_view category_group_name) const255 bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
256     std::string_view category_group_name) const {
257   return category_filter_.IsCategoryGroupEnabled(category_group_name);
258 }
259 
260 // static
TraceRecordModeToStr(TraceRecordMode record_mode)261 std::string TraceConfig::TraceRecordModeToStr(TraceRecordMode record_mode) {
262   switch (record_mode) {
263     case RECORD_UNTIL_FULL:
264       return kRecordUntilFull;
265     case RECORD_CONTINUOUSLY:
266       return kRecordContinuously;
267     case RECORD_AS_MUCH_AS_POSSIBLE:
268       return kRecordAsMuchAsPossible;
269     case ECHO_TO_CONSOLE:
270       return kTraceToConsole;
271   }
272   return kRecordUntilFull;
273 }
274 
TraceConfig()275 TraceConfig::TraceConfig() {
276   InitializeDefault();
277 }
278 
TraceConfig(std::string_view category_filter_string,std::string_view trace_options_string)279 TraceConfig::TraceConfig(std::string_view category_filter_string,
280                          std::string_view trace_options_string) {
281   InitializeFromStrings(category_filter_string, trace_options_string);
282 }
283 
TraceConfig(std::string_view category_filter_string,TraceRecordMode record_mode)284 TraceConfig::TraceConfig(std::string_view category_filter_string,
285                          TraceRecordMode record_mode) {
286   InitializeFromStrings(category_filter_string,
287                         TraceConfig::TraceRecordModeToStr(record_mode));
288 }
289 
TraceConfig(const Value::Dict & config)290 TraceConfig::TraceConfig(const Value::Dict& config) {
291   InitializeFromConfigDict(config);
292 }
293 
TraceConfig(std::string_view config_string)294 TraceConfig::TraceConfig(std::string_view config_string) {
295   if (!config_string.empty())
296     InitializeFromConfigString(config_string);
297   else
298     InitializeDefault();
299 }
300 
301 TraceConfig::TraceConfig(const TraceConfig& tc) = default;
302 
303 TraceConfig::~TraceConfig() = default;
304 
operator =(const TraceConfig & rhs)305 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
306   if (this == &rhs)
307     return *this;
308 
309   record_mode_ = rhs.record_mode_;
310   trace_buffer_size_in_events_ = rhs.trace_buffer_size_in_events_;
311   trace_buffer_size_in_kb_ = rhs.trace_buffer_size_in_kb_;
312   enable_systrace_ = rhs.enable_systrace_;
313   enable_argument_filter_ = rhs.enable_argument_filter_;
314   category_filter_ = rhs.category_filter_;
315   process_filter_config_ = rhs.process_filter_config_;
316   enable_event_package_name_filter_ = rhs.enable_event_package_name_filter_;
317   memory_dump_config_ = rhs.memory_dump_config_;
318   event_filters_ = rhs.event_filters_;
319   histogram_names_ = rhs.histogram_names_;
320   systrace_events_ = rhs.systrace_events_;
321   return *this;
322 }
323 
IsEquivalentTo(const TraceConfig & other) const324 bool TraceConfig::IsEquivalentTo(const TraceConfig& other) const {
325   if (enable_systrace_ != other.enable_systrace_ ||
326       enable_argument_filter_ != other.enable_argument_filter_ ||
327       enable_event_package_name_filter_ !=
328           other.enable_event_package_name_filter_ ||
329       histogram_names_ != other.histogram_names_ ||
330       systrace_events_ != other.systrace_events_ ||
331       process_filter_config_ != other.process_filter_config_ ||
332       memory_dump_config_ != other.memory_dump_config_ ||
333       !category_filter_.IsEquivalentTo(other.category_filter_)) {
334     return false;
335   }
336 
337   if (event_filters_.size() != other.event_filters_.size()) {
338     return false;
339   }
340   for (const auto& filter : event_filters_) {
341     bool equivalent_found = false;
342     for (const auto& other_filter : other.event_filters_) {
343       if (other_filter.IsEquivalentTo(filter)) {
344         equivalent_found = true;
345         break;
346       }
347     }
348     if (!equivalent_found) {
349       return false;
350     }
351   }
352 
353   return true;
354 }
355 
ToString() const356 std::string TraceConfig::ToString() const {
357   Value dict = ToValue();
358   std::string json;
359   JSONWriter::Write(dict, &json);
360   return json;
361 }
362 
363 std::unique_ptr<ConvertableToTraceFormat>
AsConvertableToTraceFormat() const364 TraceConfig::AsConvertableToTraceFormat() const {
365   return std::make_unique<ConvertableTraceConfigToTraceFormat>(*this);
366 }
367 
ToCategoryFilterString() const368 std::string TraceConfig::ToCategoryFilterString() const {
369   return category_filter_.ToFilterString();
370 }
371 
IsCategoryGroupEnabled(std::string_view category_group_name) const372 bool TraceConfig::IsCategoryGroupEnabled(
373     std::string_view category_group_name) const {
374   // TraceLog should call this method only as part of enabling/disabling
375   // categories.
376   return category_filter_.IsCategoryGroupEnabled(category_group_name);
377 }
378 
Merge(const TraceConfig & config)379 void TraceConfig::Merge(const TraceConfig& config) {
380   if (record_mode_ != config.record_mode_ ||
381       enable_systrace_ != config.enable_systrace_ ||
382       enable_argument_filter_ != config.enable_argument_filter_ ||
383       enable_event_package_name_filter_ !=
384           config.enable_event_package_name_filter_) {
385     DLOG(ERROR) << "Attempting to merge trace config with a different "
386                 << "set of options.";
387   }
388   DCHECK_EQ(trace_buffer_size_in_events_, config.trace_buffer_size_in_events_)
389       << "Cannot change trace buffer size";
390 
391   category_filter_.Merge(config.category_filter_);
392   memory_dump_config_.Merge(config.memory_dump_config_);
393   process_filter_config_.Merge(config.process_filter_config_);
394 
395   event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
396                         config.event_filters().end());
397   histogram_names_.insert(config.histogram_names().begin(),
398                           config.histogram_names().end());
399 }
400 
Clear()401 void TraceConfig::Clear() {
402   record_mode_ = RECORD_UNTIL_FULL;
403   trace_buffer_size_in_events_ = 0;
404   trace_buffer_size_in_kb_ = 0;
405   enable_systrace_ = false;
406   enable_argument_filter_ = false;
407   enable_event_package_name_filter_ = false;
408   category_filter_.Clear();
409   memory_dump_config_.Clear();
410   process_filter_config_.Clear();
411   event_filters_.clear();
412   histogram_names_.clear();
413   systrace_events_.clear();
414 }
415 
InitializeDefault()416 void TraceConfig::InitializeDefault() {
417   record_mode_ = RECORD_UNTIL_FULL;
418   trace_buffer_size_in_events_ = 0;
419   trace_buffer_size_in_kb_ = 0;
420   enable_systrace_ = false;
421   enable_argument_filter_ = false;
422   enable_event_package_name_filter_ = false;
423 }
424 
InitializeFromConfigDict(const Value::Dict & dict)425 void TraceConfig::InitializeFromConfigDict(const Value::Dict& dict) {
426   record_mode_ = RECORD_UNTIL_FULL;
427   const std::string* record_mode = dict.FindString(kRecordModeParam);
428   if (record_mode) {
429     if (*record_mode == kRecordUntilFull) {
430       record_mode_ = RECORD_UNTIL_FULL;
431     } else if (*record_mode == kRecordContinuously) {
432       record_mode_ = RECORD_CONTINUOUSLY;
433     } else if (*record_mode == kTraceToConsole) {
434       record_mode_ = ECHO_TO_CONSOLE;
435     } else if (*record_mode == kRecordAsMuchAsPossible) {
436       record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
437     }
438   }
439   trace_buffer_size_in_events_ = base::saturated_cast<size_t>(
440       dict.FindInt(kTraceBufferSizeInEvents).value_or(0));
441   trace_buffer_size_in_kb_ = base::saturated_cast<size_t>(
442       dict.FindInt(kTraceBufferSizeInKb).value_or(0));
443 
444   enable_systrace_ = dict.FindBool(kEnableSystraceParam).value_or(false);
445   enable_argument_filter_ =
446       dict.FindBool(kEnableArgumentFilterParam).value_or(false);
447   enable_event_package_name_filter_ =
448       dict.FindBool(kEnableEventPackageNameFilterParam).value_or(false);
449 
450   category_filter_.InitializeFromConfigDict(dict);
451   process_filter_config_.InitializeFromConfigDict(dict);
452 
453   const Value::List* category_event_filters = dict.FindList(kEventFiltersParam);
454   if (category_event_filters)
455     SetEventFiltersFromConfigList(*category_event_filters);
456   const Value::List* histogram_names = dict.FindList(kHistogramNamesParam);
457   if (histogram_names)
458     SetHistogramNamesFromConfigList(*histogram_names);
459 
460   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
461     // If dump triggers not set, the client is using the legacy with just
462     // category enabled. So, use the default periodic dump config.
463     const Value::Dict* memory_dump_config =
464         dict.FindDict(kMemoryDumpConfigParam);
465     if (memory_dump_config)
466       SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
467     else
468       SetDefaultMemoryDumpConfig();
469   }
470 
471   systrace_events_.clear();
472   if (enable_systrace_) {
473     const Value::List* systrace_events = dict.FindList(kSystraceEventsParam);
474     if (systrace_events) {
475       for (const Value& value : *systrace_events) {
476         systrace_events_.insert(value.GetString());
477       }
478     }
479   }
480 }
481 
InitializeFromConfigString(std::string_view config_string)482 void TraceConfig::InitializeFromConfigString(std::string_view config_string) {
483   std::optional<Value> dict = JSONReader::Read(config_string);
484   if (dict && dict->is_dict())
485     InitializeFromConfigDict(dict->GetDict());
486   else
487     InitializeDefault();
488 }
489 
InitializeFromStrings(std::string_view category_filter_string,std::string_view trace_options_string)490 void TraceConfig::InitializeFromStrings(std::string_view category_filter_string,
491                                         std::string_view trace_options_string) {
492   if (!category_filter_string.empty())
493     category_filter_.InitializeFromString(category_filter_string);
494 
495   record_mode_ = RECORD_UNTIL_FULL;
496   trace_buffer_size_in_events_ = 0;
497   trace_buffer_size_in_kb_ = 0;
498   enable_systrace_ = false;
499   systrace_events_.clear();
500   enable_argument_filter_ = false;
501   enable_event_package_name_filter_ = false;
502   if (!trace_options_string.empty()) {
503     std::vector<std::string> split =
504         SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
505     for (const std::string& token : split) {
506       if (token == kRecordUntilFull) {
507         record_mode_ = RECORD_UNTIL_FULL;
508       } else if (token == kRecordContinuously) {
509         record_mode_ = RECORD_CONTINUOUSLY;
510       } else if (token == kTraceToConsole) {
511         record_mode_ = ECHO_TO_CONSOLE;
512       } else if (token == kRecordAsMuchAsPossible) {
513         record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
514       } else if (token.find(kEnableSystrace) == 0) {
515         // Find optional events list.
516         const size_t length = token.length();
517         if (length == kEnableSystraceLength) {
518           // Use all predefined categories.
519           enable_systrace_ = true;
520           continue;
521         }
522         const auto system_events_not_trimmed =
523             token.substr(kEnableSystraceLength);
524         const auto system_events =
525             TrimString(system_events_not_trimmed, kWhitespaceASCII, TRIM_ALL);
526         if (system_events[0] != '=') {
527           LOG(ERROR) << "Failed to parse " << token;
528           continue;
529         }
530         enable_systrace_ = true;
531         const std::vector<std::string> split_systrace_events = SplitString(
532             system_events.substr(1), " ", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
533         for (const std::string& systrace_event : split_systrace_events)
534           systrace_events_.insert(systrace_event);
535       } else if (token == kEnableArgumentFilter) {
536         enable_argument_filter_ = true;
537       }
538     }
539   }
540 
541   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
542     SetDefaultMemoryDumpConfig();
543   }
544 }
545 
SetMemoryDumpConfigFromConfigDict(const Value::Dict & memory_dump_config)546 void TraceConfig::SetMemoryDumpConfigFromConfigDict(
547     const Value::Dict& memory_dump_config) {
548   // Set allowed dump modes.
549   memory_dump_config_.allowed_dump_modes.clear();
550   const Value::List* allowed_modes_list =
551       memory_dump_config.FindList(kAllowedDumpModesParam);
552   if (allowed_modes_list) {
553     for (const Value& item : *allowed_modes_list) {
554       DCHECK(item.is_string());
555       memory_dump_config_.allowed_dump_modes.insert(
556           StringToMemoryDumpLevelOfDetail(item.GetString()));
557     }
558   } else {
559     // If allowed modes param is not given then allow all modes by default.
560     memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
561   }
562 
563   // Set triggers
564   memory_dump_config_.triggers.clear();
565   const Value::List* trigger_list = memory_dump_config.FindList(kTriggersParam);
566   if (trigger_list) {
567     for (const Value& trigger : *trigger_list) {
568       if (!trigger.is_dict()) {
569         continue;
570       }
571       const Value::Dict& trigger_dict = trigger.GetDict();
572 
573       MemoryDumpConfig::Trigger dump_config;
574       std::optional<int> interval = trigger_dict.FindInt(kMinTimeBetweenDumps);
575       if (!interval) {
576         // If "min_time_between_dumps_ms" param was not given, then the trace
577         // config uses old format where only periodic dumps are supported.
578         interval = trigger_dict.FindInt(kPeriodicIntervalLegacyParam);
579         dump_config.trigger_type = MemoryDumpType::kPeriodicInterval;
580       } else {
581         const std::string* trigger_type_str =
582             trigger_dict.FindString(kTriggerTypeParam);
583         DCHECK(trigger_type_str);
584         dump_config.trigger_type = StringToMemoryDumpType(*trigger_type_str);
585       }
586       DCHECK(interval.has_value());
587       DCHECK_GT(*interval, 0);
588       dump_config.min_time_between_dumps_ms = static_cast<uint32_t>(*interval);
589 
590       const std::string* level_of_detail_str =
591           trigger_dict.FindString(kTriggerModeParam);
592       DCHECK(level_of_detail_str);
593       dump_config.level_of_detail =
594           StringToMemoryDumpLevelOfDetail(*level_of_detail_str);
595 
596       memory_dump_config_.triggers.push_back(dump_config);
597     }
598   }
599 
600   // Set heap profiler options.
601   const Value::Dict* heap_profiler_options =
602       memory_dump_config.FindDict(kHeapProfilerOptions);
603   if (heap_profiler_options) {
604     std::optional<int> min_size_bytes =
605         heap_profiler_options->FindInt(kBreakdownThresholdBytes);
606     if (min_size_bytes && *min_size_bytes >= 0) {
607       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
608           static_cast<uint32_t>(*min_size_bytes);
609     } else {
610       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
611           MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
612     }
613   }
614 }
615 
SetDefaultMemoryDumpConfig()616 void TraceConfig::SetDefaultMemoryDumpConfig() {
617   memory_dump_config_.Clear();
618   memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
619 }
620 
SetProcessFilterConfig(const ProcessFilterConfig & config)621 void TraceConfig::SetProcessFilterConfig(const ProcessFilterConfig& config) {
622   process_filter_config_ = config;
623 }
624 
SetHistogramNamesFromConfigList(const Value::List & histogram_names)625 void TraceConfig::SetHistogramNamesFromConfigList(
626     const Value::List& histogram_names) {
627   histogram_names_.clear();
628   for (const Value& value : histogram_names) {
629     histogram_names_.insert(value.GetString());
630   }
631 }
632 
SetEventFiltersFromConfigList(const Value::List & category_event_filters)633 void TraceConfig::SetEventFiltersFromConfigList(
634     const Value::List& category_event_filters) {
635   event_filters_.clear();
636 
637   for (const Value& event_filter : category_event_filters) {
638     if (!event_filter.is_dict()) {
639       continue;
640     }
641     const Value::Dict& event_filter_dict = event_filter.GetDict();
642 
643     const std::string* predicate_name =
644         event_filter_dict.FindString(kFilterPredicateParam);
645     CHECK(predicate_name) << "Invalid predicate name in category event filter.";
646 
647     EventFilterConfig new_config(*predicate_name);
648     new_config.InitializeFromConfigDict(event_filter_dict);
649     event_filters_.push_back(new_config);
650   }
651 }
652 
ToValue() const653 Value TraceConfig::ToValue() const {
654   Value::Dict dict;
655   dict.Set(kRecordModeParam, TraceConfig::TraceRecordModeToStr(record_mode_));
656   dict.Set(kEnableSystraceParam, enable_systrace_);
657   dict.Set(kEnableArgumentFilterParam, enable_argument_filter_);
658   if (trace_buffer_size_in_events_ > 0) {
659     dict.Set(kTraceBufferSizeInEvents,
660              base::checked_cast<int>(trace_buffer_size_in_events_));
661   }
662   if (trace_buffer_size_in_kb_ > 0) {
663     dict.Set(kTraceBufferSizeInKb,
664              base::checked_cast<int>(trace_buffer_size_in_kb_));
665   }
666 
667   dict.Set(kEnableEventPackageNameFilterParam,
668            enable_event_package_name_filter_);
669 
670   category_filter_.ToDict(dict);
671   process_filter_config_.ToDict(dict);
672 
673   if (!event_filters_.empty()) {
674     Value::List filter_list;
675     for (const EventFilterConfig& filter : event_filters_) {
676       Value::Dict filter_dict;
677       filter.ToDict(filter_dict);
678       filter_list.Append(std::move(filter_dict));
679     }
680     dict.Set(kEventFiltersParam, std::move(filter_list));
681   }
682 
683   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
684     Value::List allowed_modes;
685     for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
686       allowed_modes.Append(MemoryDumpLevelOfDetailToString(dump_mode));
687 
688     Value::Dict memory_dump_config;
689     memory_dump_config.Set(kAllowedDumpModesParam, std::move(allowed_modes));
690 
691     Value::List triggers_list;
692     for (const auto& config : memory_dump_config_.triggers) {
693       Value::Dict trigger_dict;
694 
695       trigger_dict.Set(kTriggerTypeParam,
696                        MemoryDumpTypeToString(config.trigger_type));
697       trigger_dict.Set(kMinTimeBetweenDumps,
698                        static_cast<int>(config.min_time_between_dumps_ms));
699       trigger_dict.Set(kTriggerModeParam,
700                        MemoryDumpLevelOfDetailToString(config.level_of_detail));
701       triggers_list.Append(std::move(trigger_dict));
702     }
703 
704     // Empty triggers will still be specified explicitly since it means that
705     // the periodic dumps are not enabled.
706     memory_dump_config.Set(kTriggersParam, std::move(triggers_list));
707 
708     if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
709         MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
710       Value::Dict options;
711       options.Set(
712           kBreakdownThresholdBytes,
713           base::checked_cast<int>(memory_dump_config_.heap_profiler_options
714                                       .breakdown_threshold_bytes));
715       memory_dump_config.Set(kHeapProfilerOptions, std::move(options));
716     }
717     dict.Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
718   }
719 
720   if (!histogram_names_.empty()) {
721     base::Value::List histogram_names;
722     for (const std::string& histogram_name : histogram_names_)
723       histogram_names.Append(histogram_name);
724     dict.Set(kHistogramNamesParam, std::move(histogram_names));
725   }
726 
727   if (enable_systrace_) {
728     if (!systrace_events_.empty()) {
729       base::Value::List systrace_events;
730       for (const std::string& systrace_event : systrace_events_)
731         systrace_events.Append(systrace_event);
732       dict.Set(kSystraceEventsParam, std::move(systrace_events));
733     }
734   }
735 
736   return Value(std::move(dict));
737 }
738 
EnableSystraceEvent(const std::string & systrace_event)739 void TraceConfig::EnableSystraceEvent(const std::string& systrace_event) {
740   systrace_events_.insert(systrace_event);
741 }
742 
EnableHistogram(const std::string & histogram_name)743 void TraceConfig::EnableHistogram(const std::string& histogram_name) {
744   histogram_names_.insert(histogram_name);
745 }
746 
ToTraceOptionsString() const747 std::string TraceConfig::ToTraceOptionsString() const {
748   std::string ret;
749   switch (record_mode_) {
750     case RECORD_UNTIL_FULL:
751       ret = kRecordUntilFull;
752       break;
753     case RECORD_CONTINUOUSLY:
754       ret = kRecordContinuously;
755       break;
756     case RECORD_AS_MUCH_AS_POSSIBLE:
757       ret = kRecordAsMuchAsPossible;
758       break;
759     case ECHO_TO_CONSOLE:
760       ret = kTraceToConsole;
761       break;
762   }
763   if (enable_systrace_) {
764     ret += ",";
765     ret += kEnableSystrace;
766     bool first_param = true;
767     for (const std::string& systrace_event : systrace_events_) {
768       if (first_param) {
769         ret += "=";
770         first_param = false;
771       } else {
772         ret += " ";
773       }
774       ret = ret + systrace_event;
775     }
776   }
777   if (enable_argument_filter_) {
778     ret += ",";
779     ret += kEnableArgumentFilter;
780   }
781   return ret;
782 }
783 
ToPerfettoTrackEventConfigRaw(bool privacy_filtering_enabled) const784 std::string TraceConfig::ToPerfettoTrackEventConfigRaw(
785     bool privacy_filtering_enabled) const {
786   perfetto::protos::gen::TrackEventConfig te_cfg;
787   if (!base::Contains(category_filter_.excluded_categories(), "*") &&
788       !base::Contains(category_filter_.included_categories(), "*")) {
789     // In the case when the default behavior is not specified, apply the
790     // following rule: if no categories are explicitly enabled, enable the
791     // default ones; otherwise only enable matching categories.
792     if (category_filter_.included_categories().empty()) {
793       te_cfg.add_enabled_categories("*");
794     } else {
795       te_cfg.add_disabled_categories("*");
796     }
797   }
798   for (const auto& excluded : category_filter_.excluded_categories()) {
799     te_cfg.add_disabled_categories(excluded);
800   }
801   for (const auto& included : category_filter_.included_categories()) {
802     te_cfg.add_enabled_categories(included);
803   }
804   for (const auto& disabled : category_filter_.disabled_categories()) {
805     te_cfg.add_enabled_categories(disabled);
806   }
807   // Metadata is always enabled.
808   te_cfg.add_enabled_categories("__metadata");
809   te_cfg.set_enable_thread_time_sampling(true);
810   te_cfg.set_timestamp_unit_multiplier(1000);
811   if (privacy_filtering_enabled) {
812     te_cfg.set_filter_dynamic_event_names(true);
813     te_cfg.set_filter_debug_annotations(true);
814   }
815   return te_cfg.SerializeAsString();
816 }
817 
818 }  // namespace base::trace_event
819