• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <utility>
10 
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/strings/string_split.h"
15 #include "base/trace_event/memory_dump_manager.h"
16 #include "base/trace_event/memory_dump_request_args.h"
17 #include "base/trace_event/trace_event.h"
18 
19 namespace base {
20 namespace trace_event {
21 
22 namespace {
23 
24 // String options that can be used to initialize TraceOptions.
25 const char kRecordUntilFull[] = "record-until-full";
26 const char kRecordContinuously[] = "record-continuously";
27 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
28 const char kTraceToConsole[] = "trace-to-console";
29 const char kEnableSystrace[] = "enable-systrace";
30 const char kEnableArgumentFilter[] = "enable-argument-filter";
31 
32 // String parameters that can be used to parse the trace config string.
33 const char kRecordModeParam[] = "record_mode";
34 const char kEnableSystraceParam[] = "enable_systrace";
35 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
36 
37 // String parameters that is used to parse memory dump config in trace config
38 // string.
39 const char kMemoryDumpConfigParam[] = "memory_dump_config";
40 const char kAllowedDumpModesParam[] = "allowed_dump_modes";
41 const char kTriggersParam[] = "triggers";
42 const char kTriggerModeParam[] = "mode";
43 const char kMinTimeBetweenDumps[] = "min_time_between_dumps_ms";
44 const char kTriggerTypeParam[] = "type";
45 const char kPeriodicIntervalLegacyParam[] = "periodic_interval_ms";
46 const char kHeapProfilerOptions[] = "heap_profiler_options";
47 const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
48 
49 // String parameters used to parse category event filters.
50 const char kEventFiltersParam[] = "event_filters";
51 const char kFilterPredicateParam[] = "filter_predicate";
52 const char kFilterArgsParam[] = "filter_args";
53 
54 // String parameter used to parse process filter.
55 const char kIncludedProcessesParam[] = "included_process_ids";
56 
57 class ConvertableTraceConfigToTraceFormat
58     : public base::trace_event::ConvertableToTraceFormat {
59  public:
ConvertableTraceConfigToTraceFormat(const TraceConfig & trace_config)60   explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
61       : trace_config_(trace_config) {}
62 
63   ~ConvertableTraceConfigToTraceFormat() override = default;
64 
AppendAsTraceFormat(std::string * out) const65   void AppendAsTraceFormat(std::string* out) const override {
66     out->append(trace_config_.ToString());
67   }
68 
69  private:
70   const TraceConfig trace_config_;
71 };
72 
GetDefaultAllowedMemoryDumpModes()73 std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
74   std::set<MemoryDumpLevelOfDetail> all_modes;
75   for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
76        mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
77     all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
78   }
79   return all_modes;
80 }
81 
82 }  // namespace
83 
HeapProfiler()84 TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
85     : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
86 
Clear()87 void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
88   breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
89 }
90 
ResetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig & memory_dump_config)91 void TraceConfig::ResetMemoryDumpConfig(
92     const TraceConfig::MemoryDumpConfig& memory_dump_config) {
93   memory_dump_config_.Clear();
94   memory_dump_config_ = memory_dump_config;
95 }
96 
97 TraceConfig::MemoryDumpConfig::MemoryDumpConfig() = default;
98 
99 TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
100     const MemoryDumpConfig& other) = default;
101 
102 TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() = default;
103 
Clear()104 void TraceConfig::MemoryDumpConfig::Clear() {
105   allowed_dump_modes.clear();
106   triggers.clear();
107   heap_profiler_options.Clear();
108 }
109 
Merge(const TraceConfig::MemoryDumpConfig & config)110 void TraceConfig::MemoryDumpConfig::Merge(
111     const TraceConfig::MemoryDumpConfig& config) {
112   triggers.insert(triggers.end(), config.triggers.begin(),
113                   config.triggers.end());
114   allowed_dump_modes.insert(config.allowed_dump_modes.begin(),
115                             config.allowed_dump_modes.end());
116   heap_profiler_options.breakdown_threshold_bytes =
117       std::min(heap_profiler_options.breakdown_threshold_bytes,
118                config.heap_profiler_options.breakdown_threshold_bytes);
119 }
120 
121 TraceConfig::ProcessFilterConfig::ProcessFilterConfig() = default;
122 
123 TraceConfig::ProcessFilterConfig::ProcessFilterConfig(
124     const ProcessFilterConfig& other) = default;
125 
ProcessFilterConfig(const std::unordered_set<base::ProcessId> & included_process_ids)126 TraceConfig::ProcessFilterConfig::ProcessFilterConfig(
127     const std::unordered_set<base::ProcessId>& included_process_ids)
128     : included_process_ids_(included_process_ids) {}
129 
130 TraceConfig::ProcessFilterConfig::~ProcessFilterConfig() = default;
131 
Clear()132 void TraceConfig::ProcessFilterConfig::Clear() {
133   included_process_ids_.clear();
134 }
135 
Merge(const ProcessFilterConfig & config)136 void TraceConfig::ProcessFilterConfig::Merge(
137     const ProcessFilterConfig& config) {
138   included_process_ids_.insert(config.included_process_ids_.begin(),
139                                config.included_process_ids_.end());
140 }
141 
InitializeFromConfigDict(const base::DictionaryValue & dict)142 void TraceConfig::ProcessFilterConfig::InitializeFromConfigDict(
143     const base::DictionaryValue& dict) {
144   included_process_ids_.clear();
145   const Value* value =
146       dict.FindKeyOfType(kIncludedProcessesParam, Value::Type::LIST);
147   if (!value)
148     return;
149   for (auto& pid_value : value->GetList()) {
150     if (pid_value.is_int())
151       included_process_ids_.insert(pid_value.GetInt());
152   }
153 }
154 
ToDict(DictionaryValue * dict) const155 void TraceConfig::ProcessFilterConfig::ToDict(DictionaryValue* dict) const {
156   if (included_process_ids_.empty())
157     return;
158   Value* list = dict->SetKey(kIncludedProcessesParam, Value(Value::Type::LIST));
159   std::set<base::ProcessId> ordered_set(included_process_ids_.begin(),
160                                         included_process_ids_.end());
161   for (auto process_id : ordered_set)
162     list->GetList().emplace_back(static_cast<int>(process_id));
163 }
164 
IsEnabled(base::ProcessId process_id) const165 bool TraceConfig::ProcessFilterConfig::IsEnabled(
166     base::ProcessId process_id) const {
167   return included_process_ids_.empty() ||
168          included_process_ids_.count(process_id);
169 }
170 
EventFilterConfig(const std::string & predicate_name)171 TraceConfig::EventFilterConfig::EventFilterConfig(
172     const std::string& predicate_name)
173     : predicate_name_(predicate_name) {}
174 
175 TraceConfig::EventFilterConfig::~EventFilterConfig() = default;
176 
EventFilterConfig(const EventFilterConfig & tc)177 TraceConfig::EventFilterConfig::EventFilterConfig(const EventFilterConfig& tc) {
178   *this = tc;
179 }
180 
operator =(const TraceConfig::EventFilterConfig & rhs)181 TraceConfig::EventFilterConfig& TraceConfig::EventFilterConfig::operator=(
182     const TraceConfig::EventFilterConfig& rhs) {
183   if (this == &rhs)
184     return *this;
185 
186   predicate_name_ = rhs.predicate_name_;
187   category_filter_ = rhs.category_filter_;
188 
189   if (rhs.args_)
190     args_ = rhs.args_->CreateDeepCopy();
191 
192   return *this;
193 }
194 
InitializeFromConfigDict(const base::DictionaryValue * event_filter)195 void TraceConfig::EventFilterConfig::InitializeFromConfigDict(
196     const base::DictionaryValue* event_filter) {
197   category_filter_.InitializeFromConfigDict(*event_filter);
198 
199   const base::DictionaryValue* args_dict = nullptr;
200   if (event_filter->GetDictionary(kFilterArgsParam, &args_dict))
201     args_ = args_dict->CreateDeepCopy();
202 }
203 
SetCategoryFilter(const TraceConfigCategoryFilter & category_filter)204 void TraceConfig::EventFilterConfig::SetCategoryFilter(
205     const TraceConfigCategoryFilter& category_filter) {
206   category_filter_ = category_filter;
207 }
208 
ToDict(DictionaryValue * filter_dict) const209 void TraceConfig::EventFilterConfig::ToDict(
210     DictionaryValue* filter_dict) const {
211   filter_dict->SetString(kFilterPredicateParam, predicate_name());
212 
213   category_filter_.ToDict(filter_dict);
214 
215   if (args_)
216     filter_dict->Set(kFilterArgsParam, args_->CreateDeepCopy());
217 }
218 
GetArgAsSet(const char * key,std::unordered_set<std::string> * out_set) const219 bool TraceConfig::EventFilterConfig::GetArgAsSet(
220     const char* key,
221     std::unordered_set<std::string>* out_set) const {
222   const ListValue* list = nullptr;
223   if (!args_->GetList(key, &list))
224     return false;
225   for (size_t i = 0; i < list->GetSize(); ++i) {
226     std::string value;
227     if (list->GetString(i, &value))
228       out_set->insert(value);
229   }
230   return true;
231 }
232 
IsCategoryGroupEnabled(const StringPiece & category_group_name) const233 bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
234     const StringPiece& category_group_name) const {
235   return category_filter_.IsCategoryGroupEnabled(category_group_name);
236 }
237 
238 // static
TraceRecordModeToStr(TraceRecordMode record_mode)239 std::string TraceConfig::TraceRecordModeToStr(TraceRecordMode record_mode) {
240   switch (record_mode) {
241     case RECORD_UNTIL_FULL:
242       return kRecordUntilFull;
243     case RECORD_CONTINUOUSLY:
244       return kRecordContinuously;
245     case RECORD_AS_MUCH_AS_POSSIBLE:
246       return kRecordAsMuchAsPossible;
247     case ECHO_TO_CONSOLE:
248       return kTraceToConsole;
249     default:
250       NOTREACHED();
251   }
252   return kRecordUntilFull;
253 }
254 
TraceConfig()255 TraceConfig::TraceConfig() {
256   InitializeDefault();
257 }
258 
TraceConfig(StringPiece category_filter_string,StringPiece trace_options_string)259 TraceConfig::TraceConfig(StringPiece category_filter_string,
260                          StringPiece trace_options_string) {
261   InitializeFromStrings(category_filter_string, trace_options_string);
262 }
263 
TraceConfig(StringPiece category_filter_string,TraceRecordMode record_mode)264 TraceConfig::TraceConfig(StringPiece category_filter_string,
265                          TraceRecordMode record_mode) {
266   InitializeFromStrings(category_filter_string,
267                         TraceConfig::TraceRecordModeToStr(record_mode));
268 }
269 
TraceConfig(const DictionaryValue & config)270 TraceConfig::TraceConfig(const DictionaryValue& config) {
271   InitializeFromConfigDict(config);
272 }
273 
TraceConfig(StringPiece config_string)274 TraceConfig::TraceConfig(StringPiece config_string) {
275   if (!config_string.empty())
276     InitializeFromConfigString(config_string);
277   else
278     InitializeDefault();
279 }
280 
281 TraceConfig::TraceConfig(const TraceConfig& tc) = default;
282 
283 TraceConfig::~TraceConfig() = default;
284 
operator =(const TraceConfig & rhs)285 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
286   if (this == &rhs)
287     return *this;
288 
289   record_mode_ = rhs.record_mode_;
290   enable_systrace_ = rhs.enable_systrace_;
291   enable_argument_filter_ = rhs.enable_argument_filter_;
292   category_filter_ = rhs.category_filter_;
293   process_filter_config_ = rhs.process_filter_config_;
294   memory_dump_config_ = rhs.memory_dump_config_;
295   event_filters_ = rhs.event_filters_;
296   return *this;
297 }
298 
ToString() const299 std::string TraceConfig::ToString() const {
300   std::unique_ptr<DictionaryValue> dict = ToDict();
301   std::string json;
302   JSONWriter::Write(*dict, &json);
303   return json;
304 }
305 
306 std::unique_ptr<ConvertableToTraceFormat>
AsConvertableToTraceFormat() const307 TraceConfig::AsConvertableToTraceFormat() const {
308   return std::make_unique<ConvertableTraceConfigToTraceFormat>(*this);
309 }
310 
ToCategoryFilterString() const311 std::string TraceConfig::ToCategoryFilterString() const {
312   return category_filter_.ToFilterString();
313 }
314 
IsCategoryGroupEnabled(const StringPiece & category_group_name) const315 bool TraceConfig::IsCategoryGroupEnabled(
316     const StringPiece& category_group_name) const {
317   // TraceLog should call this method only as part of enabling/disabling
318   // categories.
319   return category_filter_.IsCategoryGroupEnabled(category_group_name);
320 }
321 
Merge(const TraceConfig & config)322 void TraceConfig::Merge(const TraceConfig& config) {
323   if (record_mode_ != config.record_mode_
324       || enable_systrace_ != config.enable_systrace_
325       || enable_argument_filter_ != config.enable_argument_filter_) {
326     DLOG(ERROR) << "Attempting to merge trace config with a different "
327                 << "set of options.";
328   }
329 
330   category_filter_.Merge(config.category_filter_);
331   memory_dump_config_.Merge(config.memory_dump_config_);
332   process_filter_config_.Merge(config.process_filter_config_);
333 
334   event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
335                         config.event_filters().end());
336 }
337 
Clear()338 void TraceConfig::Clear() {
339   record_mode_ = RECORD_UNTIL_FULL;
340   enable_systrace_ = false;
341   enable_argument_filter_ = false;
342   category_filter_.Clear();
343   memory_dump_config_.Clear();
344   process_filter_config_.Clear();
345   event_filters_.clear();
346 }
347 
InitializeDefault()348 void TraceConfig::InitializeDefault() {
349   record_mode_ = RECORD_UNTIL_FULL;
350   enable_systrace_ = false;
351   enable_argument_filter_ = false;
352 }
353 
InitializeFromConfigDict(const DictionaryValue & dict)354 void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
355   record_mode_ = RECORD_UNTIL_FULL;
356   std::string record_mode;
357   if (dict.GetString(kRecordModeParam, &record_mode)) {
358     if (record_mode == kRecordUntilFull) {
359       record_mode_ = RECORD_UNTIL_FULL;
360     } else if (record_mode == kRecordContinuously) {
361       record_mode_ = RECORD_CONTINUOUSLY;
362     } else if (record_mode == kTraceToConsole) {
363       record_mode_ = ECHO_TO_CONSOLE;
364     } else if (record_mode == kRecordAsMuchAsPossible) {
365       record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
366     }
367   }
368 
369   bool val;
370   enable_systrace_ = dict.GetBoolean(kEnableSystraceParam, &val) ? val : false;
371   enable_argument_filter_ =
372       dict.GetBoolean(kEnableArgumentFilterParam, &val) ? val : false;
373 
374   category_filter_.InitializeFromConfigDict(dict);
375   process_filter_config_.InitializeFromConfigDict(dict);
376 
377   const base::ListValue* category_event_filters = nullptr;
378   if (dict.GetList(kEventFiltersParam, &category_event_filters))
379     SetEventFiltersFromConfigList(*category_event_filters);
380 
381   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
382     // If dump triggers not set, the client is using the legacy with just
383     // category enabled. So, use the default periodic dump config.
384     const DictionaryValue* memory_dump_config = nullptr;
385     if (dict.GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
386       SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
387     else
388       SetDefaultMemoryDumpConfig();
389   }
390 }
391 
InitializeFromConfigString(StringPiece config_string)392 void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
393   auto dict = DictionaryValue::From(JSONReader::Read(config_string));
394   if (dict)
395     InitializeFromConfigDict(*dict);
396   else
397     InitializeDefault();
398 }
399 
InitializeFromStrings(StringPiece category_filter_string,StringPiece trace_options_string)400 void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
401                                         StringPiece trace_options_string) {
402   if (!category_filter_string.empty())
403     category_filter_.InitializeFromString(category_filter_string);
404 
405   record_mode_ = RECORD_UNTIL_FULL;
406   enable_systrace_ = false;
407   enable_argument_filter_ = false;
408   if (!trace_options_string.empty()) {
409     std::vector<std::string> split =
410         SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
411     for (const std::string& token : split) {
412       if (token == kRecordUntilFull) {
413         record_mode_ = RECORD_UNTIL_FULL;
414       } else if (token == kRecordContinuously) {
415         record_mode_ = RECORD_CONTINUOUSLY;
416       } else if (token == kTraceToConsole) {
417         record_mode_ = ECHO_TO_CONSOLE;
418       } else if (token == kRecordAsMuchAsPossible) {
419         record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
420       } else if (token == kEnableSystrace) {
421         enable_systrace_ = true;
422       } else if (token == kEnableArgumentFilter) {
423         enable_argument_filter_ = true;
424       }
425     }
426   }
427 
428   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
429     SetDefaultMemoryDumpConfig();
430   }
431 }
432 
SetMemoryDumpConfigFromConfigDict(const DictionaryValue & memory_dump_config)433 void TraceConfig::SetMemoryDumpConfigFromConfigDict(
434     const DictionaryValue& memory_dump_config) {
435   // Set allowed dump modes.
436   memory_dump_config_.allowed_dump_modes.clear();
437   const ListValue* allowed_modes_list;
438   if (memory_dump_config.GetList(kAllowedDumpModesParam, &allowed_modes_list)) {
439     for (size_t i = 0; i < allowed_modes_list->GetSize(); ++i) {
440       std::string level_of_detail_str;
441       allowed_modes_list->GetString(i, &level_of_detail_str);
442       memory_dump_config_.allowed_dump_modes.insert(
443           StringToMemoryDumpLevelOfDetail(level_of_detail_str));
444     }
445   } else {
446     // If allowed modes param is not given then allow all modes by default.
447     memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
448   }
449 
450   // Set triggers
451   memory_dump_config_.triggers.clear();
452   const ListValue* trigger_list = nullptr;
453   if (memory_dump_config.GetList(kTriggersParam, &trigger_list) &&
454       trigger_list->GetSize() > 0) {
455     for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
456       const DictionaryValue* trigger = nullptr;
457       if (!trigger_list->GetDictionary(i, &trigger))
458         continue;
459 
460       MemoryDumpConfig::Trigger dump_config;
461       int interval = 0;
462       if (!trigger->GetInteger(kMinTimeBetweenDumps, &interval)) {
463         // If "min_time_between_dumps_ms" param was not given, then the trace
464         // config uses old format where only periodic dumps are supported.
465         trigger->GetInteger(kPeriodicIntervalLegacyParam, &interval);
466         dump_config.trigger_type = MemoryDumpType::PERIODIC_INTERVAL;
467       } else {
468         std::string trigger_type_str;
469         trigger->GetString(kTriggerTypeParam, &trigger_type_str);
470         dump_config.trigger_type = StringToMemoryDumpType(trigger_type_str);
471       }
472       DCHECK_GT(interval, 0);
473       dump_config.min_time_between_dumps_ms = static_cast<uint32_t>(interval);
474 
475       std::string level_of_detail_str;
476       trigger->GetString(kTriggerModeParam, &level_of_detail_str);
477       dump_config.level_of_detail =
478           StringToMemoryDumpLevelOfDetail(level_of_detail_str);
479 
480       memory_dump_config_.triggers.push_back(dump_config);
481     }
482   }
483 
484   // Set heap profiler options
485   const DictionaryValue* heap_profiler_options = nullptr;
486   if (memory_dump_config.GetDictionary(kHeapProfilerOptions,
487                                        &heap_profiler_options)) {
488     int min_size_bytes = 0;
489     if (heap_profiler_options->GetInteger(kBreakdownThresholdBytes,
490                                          &min_size_bytes)
491         && min_size_bytes >= 0) {
492       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
493           static_cast<size_t>(min_size_bytes);
494     } else {
495       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
496           MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
497     }
498   }
499 }
500 
SetDefaultMemoryDumpConfig()501 void TraceConfig::SetDefaultMemoryDumpConfig() {
502   memory_dump_config_.Clear();
503   memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
504 }
505 
SetProcessFilterConfig(const ProcessFilterConfig & config)506 void TraceConfig::SetProcessFilterConfig(const ProcessFilterConfig& config) {
507   process_filter_config_ = config;
508 }
509 
SetEventFiltersFromConfigList(const base::ListValue & category_event_filters)510 void TraceConfig::SetEventFiltersFromConfigList(
511     const base::ListValue& category_event_filters) {
512   event_filters_.clear();
513 
514   for (size_t event_filter_index = 0;
515        event_filter_index < category_event_filters.GetSize();
516        ++event_filter_index) {
517     const base::DictionaryValue* event_filter = nullptr;
518     if (!category_event_filters.GetDictionary(event_filter_index,
519                                               &event_filter))
520       continue;
521 
522     std::string predicate_name;
523     CHECK(event_filter->GetString(kFilterPredicateParam, &predicate_name))
524         << "Invalid predicate name in category event filter.";
525 
526     EventFilterConfig new_config(predicate_name);
527     new_config.InitializeFromConfigDict(event_filter);
528     event_filters_.push_back(new_config);
529   }
530 }
531 
ToDict() const532 std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
533   auto dict = std::make_unique<DictionaryValue>();
534   dict->SetString(kRecordModeParam,
535                   TraceConfig::TraceRecordModeToStr(record_mode_));
536   dict->SetBoolean(kEnableSystraceParam, enable_systrace_);
537   dict->SetBoolean(kEnableArgumentFilterParam, enable_argument_filter_);
538 
539   category_filter_.ToDict(dict.get());
540   process_filter_config_.ToDict(dict.get());
541 
542   if (!event_filters_.empty()) {
543     std::unique_ptr<base::ListValue> filter_list(new base::ListValue());
544     for (const EventFilterConfig& filter : event_filters_) {
545       std::unique_ptr<base::DictionaryValue> filter_dict(
546           new base::DictionaryValue());
547       filter.ToDict(filter_dict.get());
548       filter_list->Append(std::move(filter_dict));
549     }
550     dict->Set(kEventFiltersParam, std::move(filter_list));
551   }
552 
553   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
554     auto allowed_modes = std::make_unique<ListValue>();
555     for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
556       allowed_modes->AppendString(MemoryDumpLevelOfDetailToString(dump_mode));
557 
558     auto memory_dump_config = std::make_unique<DictionaryValue>();
559     memory_dump_config->Set(kAllowedDumpModesParam, std::move(allowed_modes));
560 
561     auto triggers_list = std::make_unique<ListValue>();
562     for (const auto& config : memory_dump_config_.triggers) {
563       auto trigger_dict = std::make_unique<DictionaryValue>();
564       trigger_dict->SetString(kTriggerTypeParam,
565                               MemoryDumpTypeToString(config.trigger_type));
566       trigger_dict->SetInteger(
567           kMinTimeBetweenDumps,
568           static_cast<int>(config.min_time_between_dumps_ms));
569       trigger_dict->SetString(
570           kTriggerModeParam,
571           MemoryDumpLevelOfDetailToString(config.level_of_detail));
572       triggers_list->Append(std::move(trigger_dict));
573     }
574 
575     // Empty triggers will still be specified explicitly since it means that
576     // the periodic dumps are not enabled.
577     memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
578 
579     if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
580         MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
581       auto options = std::make_unique<DictionaryValue>();
582       options->SetInteger(
583           kBreakdownThresholdBytes,
584           memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
585       memory_dump_config->Set(kHeapProfilerOptions, std::move(options));
586     }
587     dict->Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
588   }
589   return dict;
590 }
591 
ToTraceOptionsString() const592 std::string TraceConfig::ToTraceOptionsString() const {
593   std::string ret;
594   switch (record_mode_) {
595     case RECORD_UNTIL_FULL:
596       ret = kRecordUntilFull;
597       break;
598     case RECORD_CONTINUOUSLY:
599       ret = kRecordContinuously;
600       break;
601     case RECORD_AS_MUCH_AS_POSSIBLE:
602       ret = kRecordAsMuchAsPossible;
603       break;
604     case ECHO_TO_CONSOLE:
605       ret = kTraceToConsole;
606       break;
607     default:
608       NOTREACHED();
609   }
610   if (enable_systrace_)
611     ret = ret + "," + kEnableSystrace;
612   if (enable_argument_filter_)
613     ret = ret + "," + kEnableArgumentFilter;
614   return ret;
615 }
616 
617 }  // namespace trace_event
618 }  // namespace base
619