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