Update V8 to version 4.6.55.
[chromium-blink-merge.git] / content / browser / tracing / tracing_controller_impl.cc
blobee280df006e7b8057695a65c764a0c7768a63a50
1 // Copyright (c) 2013 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 #include "content/browser/tracing/tracing_controller_impl.h"
6 #include "base/bind.h"
7 #include "base/files/file_util.h"
8 #include "base/json/string_escape.h"
9 #include "base/macros.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/trace_event/trace_event.h"
12 #include "content/browser/tracing/file_tracing_provider_impl.h"
13 #include "content/browser/tracing/power_tracing_agent.h"
14 #include "content/browser/tracing/trace_message_filter.h"
15 #include "content/browser/tracing/tracing_ui.h"
16 #include "content/common/child_process_messages.h"
17 #include "content/public/browser/browser_message_filter.h"
18 #include "content/public/common/child_process_host.h"
19 #include "content/public/common/content_switches.h"
21 #if defined(OS_CHROMEOS)
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/debug_daemon_client.h"
24 #endif
26 #if defined(OS_WIN)
27 #include "content/browser/tracing/etw_system_event_consumer_win.h"
28 #endif
30 using base::trace_event::TraceLog;
31 using base::trace_event::TraceConfig;
33 namespace content {
35 namespace {
37 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
38 LAZY_INSTANCE_INITIALIZER;
40 } // namespace
42 TracingController* TracingController::GetInstance() {
43 return TracingControllerImpl::GetInstance();
46 TracingControllerImpl::TracingControllerImpl()
47 : pending_disable_recording_ack_count_(0),
48 pending_capture_monitoring_snapshot_ack_count_(0),
49 pending_trace_log_status_ack_count_(0),
50 maximum_trace_buffer_usage_(0),
51 approximate_event_count_(0),
52 pending_memory_dump_ack_count_(0),
53 failed_memory_dump_count_(0),
54 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
55 // is specified in command line.
56 #if defined(OS_CHROMEOS) || defined(OS_WIN)
57 is_system_tracing_(false),
58 #endif
59 is_recording_(TraceLog::GetInstance()->IsEnabled()),
60 is_monitoring_(false),
61 is_power_tracing_(false) {
62 base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
64 // Deliberately leaked, like this class.
65 base::FileTracing::SetProvider(new FileTracingProviderImpl);
68 TracingControllerImpl::~TracingControllerImpl() {
69 // This is a Leaky instance.
70 NOTREACHED();
73 TracingControllerImpl* TracingControllerImpl::GetInstance() {
74 return g_controller.Pointer();
77 bool TracingControllerImpl::GetCategories(
78 const GetCategoriesDoneCallback& callback) {
79 DCHECK_CURRENTLY_ON(BrowserThread::UI);
81 // Known categories come back from child processes with the EndTracingAck
82 // message. So to get known categories, just begin and end tracing immediately
83 // afterwards. This will ping all the child processes for categories.
84 pending_get_categories_done_callback_ = callback;
85 if (!EnableRecording(TraceConfig("*", ""), EnableRecordingDoneCallback())) {
86 pending_get_categories_done_callback_.Reset();
87 return false;
90 bool ok = DisableRecording(NULL);
91 DCHECK(ok);
92 return true;
95 void TracingControllerImpl::SetEnabledOnFileThread(
96 const TraceConfig& trace_config,
97 int mode,
98 const base::Closure& callback) {
99 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
101 TraceLog::GetInstance()->SetEnabled(
102 trace_config, static_cast<TraceLog::Mode>(mode));
103 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
106 void TracingControllerImpl::SetDisabledOnFileThread(
107 const base::Closure& callback) {
108 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
110 TraceLog::GetInstance()->SetDisabled();
111 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
114 bool TracingControllerImpl::EnableRecording(
115 const TraceConfig& trace_config,
116 const EnableRecordingDoneCallback& callback) {
117 DCHECK_CURRENTLY_ON(BrowserThread::UI);
119 if (!can_enable_recording())
120 return false;
121 is_recording_ = true;
123 #if defined(OS_ANDROID)
124 if (pending_get_categories_done_callback_.is_null())
125 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
126 #endif
128 if (trace_config.IsSystraceEnabled()) {
129 #if defined(OS_CHROMEOS)
130 DCHECK(!is_system_tracing_);
131 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
132 StartSystemTracing();
133 is_system_tracing_ = true;
134 #elif defined(OS_WIN)
135 DCHECK(!is_system_tracing_);
136 is_system_tracing_ =
137 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
138 #endif
141 base::Closure on_enable_recording_done_callback =
142 base::Bind(&TracingControllerImpl::OnEnableRecordingDone,
143 base::Unretained(this),
144 trace_config, callback);
145 if (!BrowserThread::PostTask(
146 BrowserThread::FILE, FROM_HERE,
147 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
148 base::Unretained(this), trace_config,
149 base::trace_event::TraceLog::RECORDING_MODE,
150 on_enable_recording_done_callback))) {
151 // BrowserThread::PostTask fails if the threads haven't been created yet,
152 // so it should be safe to just use TraceLog::SetEnabled directly.
153 base::trace_event::TraceLog::GetInstance()->SetEnabled(
154 trace_config, base::trace_event::TraceLog::RECORDING_MODE);
155 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
156 on_enable_recording_done_callback);
159 return true;
162 void TracingControllerImpl::OnEnableRecordingDone(
163 const TraceConfig& trace_config,
164 const EnableRecordingDoneCallback& callback) {
165 DCHECK_CURRENTLY_ON(BrowserThread::UI);
167 // Notify all child processes.
168 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
169 it != trace_message_filters_.end(); ++it) {
170 it->get()->SendBeginTracing(trace_config);
173 if (!callback.is_null())
174 callback.Run();
177 bool TracingControllerImpl::DisableRecording(
178 const scoped_refptr<TraceDataSink>& trace_data_sink) {
179 DCHECK_CURRENTLY_ON(BrowserThread::UI);
181 if (!can_disable_recording())
182 return false;
184 trace_data_sink_ = trace_data_sink;
185 // Disable local trace early to avoid traces during end-tracing process from
186 // interfering with the process.
187 base::Closure on_disable_recording_done_callback = base::Bind(
188 &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
189 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
190 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
191 base::Unretained(this),
192 on_disable_recording_done_callback));
193 return true;
196 void TracingControllerImpl::OnDisableRecordingDone() {
197 DCHECK_CURRENTLY_ON(BrowserThread::UI);
199 #if defined(OS_ANDROID)
200 if (pending_get_categories_done_callback_.is_null())
201 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
202 #endif
204 // Count myself (local trace) in pending_disable_recording_ack_count_,
205 // acked below.
206 pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
207 pending_disable_recording_filters_ = trace_message_filters_;
209 #if defined(OS_CHROMEOS) || defined(OS_WIN)
210 if (is_system_tracing_) {
211 // Disable system tracing.
212 is_system_tracing_ = false;
213 ++pending_disable_recording_ack_count_;
215 #if defined(OS_CHROMEOS)
216 scoped_refptr<base::TaskRunner> task_runner =
217 BrowserThread::GetBlockingPool();
218 chromeos::DBusThreadManager::Get()
219 ->GetDebugDaemonClient()
220 ->RequestStopSystemTracing(
221 task_runner,
222 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
223 base::Unretained(this)));
224 #elif defined(OS_WIN)
225 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
226 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
227 base::Unretained(this)));
228 #endif
230 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
232 if (is_power_tracing_) {
233 is_power_tracing_ = false;
234 ++pending_disable_recording_ack_count_;
235 PowerTracingAgent::GetInstance()->StopTracing(
236 base::Bind(&TracingControllerImpl::OnEndPowerTracingAcked,
237 base::Unretained(this)));
240 // Handle special case of zero child processes by immediately flushing the
241 // trace log. Once the flush has completed the caller will be notified that
242 // tracing has ended.
243 if (pending_disable_recording_ack_count_ == 1) {
244 // Flush/cancel asynchronously now, because we don't have any children to
245 // wait for.
246 if (trace_data_sink_) {
247 TraceLog::GetInstance()->Flush(
248 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
249 base::Unretained(this)),
250 true);
251 } else {
252 TraceLog::GetInstance()->CancelTracing(
253 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
254 base::Unretained(this)));
258 // Notify all child processes.
259 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
260 it != trace_message_filters_.end(); ++it) {
261 if (trace_data_sink_)
262 it->get()->SendEndTracing();
263 else
264 it->get()->SendCancelTracing();
268 bool TracingControllerImpl::EnableMonitoring(
269 const TraceConfig& trace_config,
270 const EnableMonitoringDoneCallback& callback) {
271 DCHECK_CURRENTLY_ON(BrowserThread::UI);
273 if (!can_enable_monitoring())
274 return false;
275 OnMonitoringStateChanged(true);
277 #if defined(OS_ANDROID)
278 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
279 #endif
281 base::Closure on_enable_monitoring_done_callback =
282 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
283 base::Unretained(this),
284 trace_config, callback);
285 if (!BrowserThread::PostTask(
286 BrowserThread::FILE, FROM_HERE,
287 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
288 base::Unretained(this), trace_config,
289 base::trace_event::TraceLog::MONITORING_MODE,
290 on_enable_monitoring_done_callback))) {
291 // BrowserThread::PostTask fails if the threads haven't been created yet,
292 // so it should be safe to just use TraceLog::SetEnabled directly.
293 base::trace_event::TraceLog::GetInstance()->SetEnabled(
294 trace_config, base::trace_event::TraceLog::MONITORING_MODE);
295 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
296 on_enable_monitoring_done_callback);
298 return true;
301 void TracingControllerImpl::OnEnableMonitoringDone(
302 const TraceConfig& trace_config,
303 const EnableMonitoringDoneCallback& callback) {
304 DCHECK_CURRENTLY_ON(BrowserThread::UI);
306 // Notify all child processes.
307 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
308 it != trace_message_filters_.end(); ++it) {
309 it->get()->SendEnableMonitoring(trace_config);
312 if (!callback.is_null())
313 callback.Run();
316 bool TracingControllerImpl::DisableMonitoring(
317 const DisableMonitoringDoneCallback& callback) {
318 DCHECK_CURRENTLY_ON(BrowserThread::UI);
320 if (!can_disable_monitoring())
321 return false;
323 base::Closure on_disable_monitoring_done_callback =
324 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
325 base::Unretained(this), callback);
326 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
327 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
328 base::Unretained(this),
329 on_disable_monitoring_done_callback));
330 return true;
333 void TracingControllerImpl::OnDisableMonitoringDone(
334 const DisableMonitoringDoneCallback& callback) {
335 DCHECK_CURRENTLY_ON(BrowserThread::UI);
337 OnMonitoringStateChanged(false);
339 // Notify all child processes.
340 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
341 it != trace_message_filters_.end(); ++it) {
342 it->get()->SendDisableMonitoring();
344 if (!callback.is_null())
345 callback.Run();
348 void TracingControllerImpl::GetMonitoringStatus(
349 bool* out_enabled,
350 TraceConfig* out_trace_config) {
351 *out_enabled = is_monitoring_;
352 *out_trace_config = TraceLog::GetInstance()->GetCurrentTraceConfig();
355 bool TracingControllerImpl::CaptureMonitoringSnapshot(
356 const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
357 DCHECK_CURRENTLY_ON(BrowserThread::UI);
359 if (!can_disable_monitoring())
360 return false;
362 if (!monitoring_data_sink.get())
363 return false;
365 monitoring_data_sink_ = monitoring_data_sink;
367 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
368 // acked below.
369 pending_capture_monitoring_snapshot_ack_count_ =
370 trace_message_filters_.size() + 1;
371 pending_capture_monitoring_filters_ = trace_message_filters_;
373 // Handle special case of zero child processes by immediately flushing the
374 // trace log. Once the flush has completed the caller will be notified that
375 // the capture snapshot has ended.
376 if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
377 // Flush asynchronously now, because we don't have any children to wait for.
378 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
379 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
380 base::Unretained(this)));
383 // Notify all child processes.
384 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
385 it != trace_message_filters_.end(); ++it) {
386 it->get()->SendCaptureMonitoringSnapshot();
389 #if defined(OS_ANDROID)
390 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
391 #endif
393 return true;
396 bool TracingControllerImpl::GetTraceBufferUsage(
397 const GetTraceBufferUsageCallback& callback) {
398 DCHECK_CURRENTLY_ON(BrowserThread::UI);
400 if (!can_get_trace_buffer_usage() || callback.is_null())
401 return false;
403 pending_trace_buffer_usage_callback_ = callback;
405 // Count myself in pending_trace_log_status_ack_count_, acked below.
406 pending_trace_log_status_ack_count_ = trace_message_filters_.size() + 1;
407 pending_trace_log_status_filters_ = trace_message_filters_;
408 maximum_trace_buffer_usage_ = 0;
409 approximate_event_count_ = 0;
411 base::trace_event::TraceLogStatus status =
412 TraceLog::GetInstance()->GetStatus();
413 // Call OnTraceLogStatusReply unconditionally for the browser process.
414 // This will result in immediate execution of the callback if there are no
415 // child processes.
416 BrowserThread::PostTask(
417 BrowserThread::UI, FROM_HERE,
418 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
419 base::Unretained(this), scoped_refptr<TraceMessageFilter>(),
420 status));
422 // Notify all child processes.
423 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
424 it != trace_message_filters_.end(); ++it) {
425 it->get()->SendGetTraceLogStatus();
427 return true;
430 bool TracingControllerImpl::SetWatchEvent(
431 const std::string& category_name,
432 const std::string& event_name,
433 const WatchEventCallback& callback) {
434 DCHECK_CURRENTLY_ON(BrowserThread::UI);
436 if (callback.is_null())
437 return false;
439 watch_category_name_ = category_name;
440 watch_event_name_ = event_name;
441 watch_event_callback_ = callback;
443 TraceLog::GetInstance()->SetWatchEvent(
444 category_name, event_name,
445 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
446 base::Unretained(this)));
448 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
449 it != trace_message_filters_.end(); ++it) {
450 it->get()->SendSetWatchEvent(category_name, event_name);
452 return true;
455 bool TracingControllerImpl::CancelWatchEvent() {
456 DCHECK_CURRENTLY_ON(BrowserThread::UI);
458 if (!can_cancel_watch_event())
459 return false;
461 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
462 it != trace_message_filters_.end(); ++it) {
463 it->get()->SendCancelWatchEvent();
466 watch_event_callback_.Reset();
467 return true;
470 bool TracingControllerImpl::IsRecording() const {
471 return is_recording_;
474 void TracingControllerImpl::AddTraceMessageFilter(
475 TraceMessageFilter* trace_message_filter) {
476 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
477 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
478 base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
479 base::Unretained(this),
480 make_scoped_refptr(trace_message_filter)));
481 return;
484 trace_message_filters_.insert(trace_message_filter);
485 if (can_cancel_watch_event()) {
486 trace_message_filter->SendSetWatchEvent(watch_category_name_,
487 watch_event_name_);
489 if (can_disable_recording()) {
490 trace_message_filter->SendBeginTracing(
491 TraceLog::GetInstance()->GetCurrentTraceConfig());
493 if (can_disable_monitoring()) {
494 trace_message_filter->SendEnableMonitoring(
495 TraceLog::GetInstance()->GetCurrentTraceConfig());
497 if (!trace_message_filter_added_callback_.is_null())
498 trace_message_filter_added_callback_.Run(trace_message_filter);
501 void TracingControllerImpl::RemoveTraceMessageFilter(
502 TraceMessageFilter* trace_message_filter) {
503 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
504 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
505 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
506 base::Unretained(this),
507 make_scoped_refptr(trace_message_filter)));
508 return;
511 // If a filter is removed while a response from that filter is pending then
512 // simulate the response. Otherwise the response count will be wrong and the
513 // completion callback will never be executed.
514 if (pending_disable_recording_ack_count_ > 0) {
515 TraceMessageFilterSet::const_iterator it =
516 pending_disable_recording_filters_.find(trace_message_filter);
517 if (it != pending_disable_recording_filters_.end()) {
518 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
519 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
520 base::Unretained(this),
521 make_scoped_refptr(trace_message_filter),
522 std::vector<std::string>()));
525 if (pending_capture_monitoring_snapshot_ack_count_ > 0) {
526 TraceMessageFilterSet::const_iterator it =
527 pending_capture_monitoring_filters_.find(trace_message_filter);
528 if (it != pending_capture_monitoring_filters_.end()) {
529 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
530 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
531 base::Unretained(this),
532 make_scoped_refptr(trace_message_filter)));
535 if (pending_trace_log_status_ack_count_ > 0) {
536 TraceMessageFilterSet::const_iterator it =
537 pending_trace_log_status_filters_.find(trace_message_filter);
538 if (it != pending_trace_log_status_filters_.end()) {
539 BrowserThread::PostTask(
540 BrowserThread::UI, FROM_HERE,
541 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
542 base::Unretained(this),
543 make_scoped_refptr(trace_message_filter),
544 base::trace_event::TraceLogStatus()));
547 if (pending_memory_dump_ack_count_ > 0) {
548 TraceMessageFilterSet::const_iterator it =
549 pending_memory_dump_filters_.find(trace_message_filter);
550 if (it != pending_memory_dump_filters_.end()) {
551 BrowserThread::PostTask(
552 BrowserThread::UI, FROM_HERE,
553 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
554 base::Unretained(this),
555 make_scoped_refptr(trace_message_filter),
556 pending_memory_dump_guid_, false /* success */));
559 trace_message_filters_.erase(trace_message_filter);
562 void TracingControllerImpl::OnDisableRecordingAcked(
563 TraceMessageFilter* trace_message_filter,
564 const std::vector<std::string>& known_category_groups) {
565 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
566 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
567 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
568 base::Unretained(this),
569 make_scoped_refptr(trace_message_filter),
570 known_category_groups));
571 return;
574 // Merge known_category_groups with known_category_groups_
575 known_category_groups_.insert(known_category_groups.begin(),
576 known_category_groups.end());
578 if (pending_disable_recording_ack_count_ == 0)
579 return;
581 if (trace_message_filter &&
582 !pending_disable_recording_filters_.erase(trace_message_filter)) {
583 // The response from the specified message filter has already been received.
584 return;
587 if (--pending_disable_recording_ack_count_ == 1) {
588 // All acks from subprocesses have been received. Now flush the local trace.
589 // During or after this call, our OnLocalTraceDataCollected will be
590 // called with the last of the local trace data.
591 if (trace_data_sink_) {
592 TraceLog::GetInstance()->Flush(
593 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
594 base::Unretained(this)),
595 true);
596 } else {
597 TraceLog::GetInstance()->CancelTracing(
598 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
599 base::Unretained(this)));
601 return;
604 if (pending_disable_recording_ack_count_ != 0)
605 return;
607 // All acks (including from the subprocesses and the local trace) have been
608 // received.
609 is_recording_ = false;
611 // Trigger callback if one is set.
612 if (!pending_get_categories_done_callback_.is_null()) {
613 pending_get_categories_done_callback_.Run(known_category_groups_);
614 pending_get_categories_done_callback_.Reset();
615 } else if (trace_data_sink_.get()) {
616 trace_data_sink_->Close();
617 trace_data_sink_ = NULL;
621 void TracingControllerImpl::OnEndPowerTracingAcked(
622 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
623 DCHECK_CURRENTLY_ON(BrowserThread::UI);
625 if (trace_data_sink_.get()) {
626 std::string json_string = base::GetQuotedJSONString(events_str_ptr->data());
627 trace_data_sink_->SetPowerTrace(json_string);
629 std::vector<std::string> category_groups;
630 OnDisableRecordingAcked(NULL, category_groups);
633 #if defined(OS_CHROMEOS) || defined(OS_WIN)
634 void TracingControllerImpl::OnEndSystemTracingAcked(
635 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
636 DCHECK_CURRENTLY_ON(BrowserThread::UI);
638 if (trace_data_sink_.get()) {
639 #if defined(OS_WIN)
640 // The Windows kernel events are kept into a JSon format stored as string
641 // and must not be escaped.
642 std::string json_string = events_str_ptr->data();
643 #else
644 std::string json_string =
645 base::GetQuotedJSONString(events_str_ptr->data());
646 #endif
647 trace_data_sink_->SetSystemTrace(json_string);
649 DCHECK(!is_system_tracing_);
650 std::vector<std::string> category_groups;
651 OnDisableRecordingAcked(NULL, category_groups);
653 #endif
655 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
656 TraceMessageFilter* trace_message_filter) {
657 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
658 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
659 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
660 base::Unretained(this),
661 make_scoped_refptr(trace_message_filter)));
662 return;
665 if (pending_capture_monitoring_snapshot_ack_count_ == 0)
666 return;
668 if (trace_message_filter &&
669 !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
670 // The response from the specified message filter has already been received.
671 return;
674 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
675 // All acks from subprocesses have been received. Now flush the local trace.
676 // During or after this call, our OnLocalMonitoringTraceDataCollected
677 // will be called with the last of the local trace data.
678 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
679 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
680 base::Unretained(this)));
681 return;
684 if (pending_capture_monitoring_snapshot_ack_count_ != 0)
685 return;
687 if (monitoring_data_sink_.get()) {
688 monitoring_data_sink_->Close();
689 monitoring_data_sink_ = NULL;
693 void TracingControllerImpl::OnTraceDataCollected(
694 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
695 // OnTraceDataCollected may be called from any browser thread, either by the
696 // local event trace system or from child processes via TraceMessageFilter.
697 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
698 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
699 base::Bind(&TracingControllerImpl::OnTraceDataCollected,
700 base::Unretained(this), events_str_ptr));
701 return;
704 if (trace_data_sink_.get())
705 trace_data_sink_->AddTraceChunk(events_str_ptr->data());
708 void TracingControllerImpl::OnMonitoringTraceDataCollected(
709 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
710 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
711 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
712 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
713 base::Unretained(this), events_str_ptr));
714 return;
717 if (monitoring_data_sink_.get())
718 monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
721 void TracingControllerImpl::OnLocalTraceDataCollected(
722 const scoped_refptr<base::RefCountedString>& events_str_ptr,
723 bool has_more_events) {
724 if (events_str_ptr->data().size())
725 OnTraceDataCollected(events_str_ptr);
727 if (has_more_events)
728 return;
730 // Simulate an DisableRecordingAcked for the local trace.
731 std::vector<std::string> category_groups;
732 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
733 OnDisableRecordingAcked(NULL, category_groups);
736 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
737 const scoped_refptr<base::RefCountedString>& events_str_ptr,
738 bool has_more_events) {
739 if (events_str_ptr->data().size())
740 OnMonitoringTraceDataCollected(events_str_ptr);
742 if (has_more_events)
743 return;
745 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
746 OnCaptureMonitoringSnapshotAcked(NULL);
749 void TracingControllerImpl::OnTraceLogStatusReply(
750 TraceMessageFilter* trace_message_filter,
751 const base::trace_event::TraceLogStatus& status) {
752 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
753 BrowserThread::PostTask(
754 BrowserThread::UI, FROM_HERE,
755 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
756 base::Unretained(this),
757 make_scoped_refptr(trace_message_filter), status));
758 return;
761 if (pending_trace_log_status_ack_count_ == 0)
762 return;
764 if (trace_message_filter &&
765 !pending_trace_log_status_filters_.erase(trace_message_filter)) {
766 // The response from the specified message filter has already been received.
767 return;
770 float percent_full = static_cast<float>(
771 static_cast<double>(status.event_count) / status.event_capacity);
772 maximum_trace_buffer_usage_ =
773 std::max(maximum_trace_buffer_usage_, percent_full);
774 approximate_event_count_ += status.event_count;
776 if (--pending_trace_log_status_ack_count_ == 0) {
777 // Trigger callback if one is set.
778 pending_trace_buffer_usage_callback_.Run(maximum_trace_buffer_usage_,
779 approximate_event_count_);
780 pending_trace_buffer_usage_callback_.Reset();
784 void TracingControllerImpl::OnWatchEventMatched() {
785 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
786 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
787 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
788 base::Unretained(this)));
789 return;
792 if (!watch_event_callback_.is_null())
793 watch_event_callback_.Run();
796 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
797 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
798 tracing_uis_.insert(tracing_ui);
801 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
802 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui);
803 DCHECK(it != tracing_uis_.end());
804 tracing_uis_.erase(it);
807 void TracingControllerImpl::RequestGlobalMemoryDump(
808 const base::trace_event::MemoryDumpRequestArgs& args,
809 const base::trace_event::MemoryDumpCallback& callback) {
810 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
811 BrowserThread::PostTask(
812 BrowserThread::UI, FROM_HERE,
813 base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump,
814 base::Unretained(this), args, callback));
815 return;
817 // Abort if another dump is already in progress.
818 if (pending_memory_dump_guid_) {
819 DVLOG(1) << "Requested memory dump " << args.dump_guid
820 << " while waiting for " << pending_memory_dump_guid_;
821 if (!callback.is_null())
822 callback.Run(args.dump_guid, false /* success */);
823 return;
826 // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
827 // OnBrowserProcessMemoryDumpDone().
828 pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1;
829 pending_memory_dump_filters_.clear();
830 pending_memory_dump_guid_ = args.dump_guid;
831 pending_memory_dump_callback_ = callback;
832 failed_memory_dump_count_ = 0;
834 MemoryDumpManagerDelegate::CreateProcessDump(
835 args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone,
836 base::Unretained(this)));
838 // If there are no child processes we are just done.
839 if (pending_memory_dump_ack_count_ == 1)
840 return;
842 pending_memory_dump_filters_ = trace_message_filters_;
844 for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_)
845 tmf->SendProcessMemoryDumpRequest(args);
848 bool TracingControllerImpl::IsCoordinatorProcess() const {
849 return true;
852 uint64 TracingControllerImpl::GetTracingProcessId() const {
853 return ChildProcessHost::kBrowserTracingProcessId;
856 void TracingControllerImpl::SetTraceMessageFilterAddedCallback(
857 const TraceMessageFilterAddedCallback& callback) {
858 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
859 trace_message_filter_added_callback_ = callback;
862 void TracingControllerImpl::GetTraceMessageFilters(
863 TraceMessageFilterSet* filters) {
864 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
865 filters->insert(trace_message_filters_.begin(), trace_message_filters_.end());
868 void TracingControllerImpl::OnProcessMemoryDumpResponse(
869 TraceMessageFilter* trace_message_filter,
870 uint64 dump_guid,
871 bool success) {
872 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
873 BrowserThread::PostTask(
874 BrowserThread::UI, FROM_HERE,
875 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
876 base::Unretained(this),
877 make_scoped_refptr(trace_message_filter), dump_guid,
878 success));
879 return;
882 TraceMessageFilterSet::iterator it =
883 pending_memory_dump_filters_.find(trace_message_filter);
885 if (pending_memory_dump_guid_ != dump_guid ||
886 it == pending_memory_dump_filters_.end()) {
887 DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid;
888 return;
891 DCHECK_GT(pending_memory_dump_ack_count_, 0);
892 --pending_memory_dump_ack_count_;
893 pending_memory_dump_filters_.erase(it);
894 if (!success) {
895 ++failed_memory_dump_count_;
896 DLOG(WARNING) << "Global memory dump failed because of NACK from child "
897 << trace_message_filter->peer_pid();
899 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
902 void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64 dump_guid,
903 bool success) {
904 DCHECK_GT(pending_memory_dump_ack_count_, 0);
905 --pending_memory_dump_ack_count_;
906 if (!success) {
907 ++failed_memory_dump_count_;
908 DLOG(WARNING) << "Global memory dump aborted on the current process";
910 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
913 void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
914 if (pending_memory_dump_ack_count_ > 0)
915 return;
917 DCHECK_NE(0u, pending_memory_dump_guid_);
918 const bool global_success = failed_memory_dump_count_ == 0;
919 if (!pending_memory_dump_callback_.is_null()) {
920 pending_memory_dump_callback_.Run(pending_memory_dump_guid_,
921 global_success);
922 pending_memory_dump_callback_.Reset();
924 pending_memory_dump_guid_ = 0;
927 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
928 if (is_monitoring_ == is_monitoring)
929 return;
931 is_monitoring_ = is_monitoring;
932 #if !defined(OS_ANDROID)
933 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
934 it != tracing_uis_.end(); it++) {
935 (*it)->OnMonitoringStateChanged(is_monitoring);
937 #endif
940 } // namespace content