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