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