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"
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/trace_message_filter.h"
13 #include "content/browser/tracing/tracing_ui.h"
14 #include "content/common/child_process_messages.h"
15 #include "content/public/browser/browser_message_filter.h"
16 #include "content/public/common/content_switches.h"
18 #if defined(OS_CHROMEOS)
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/debug_daemon_client.h"
24 #include "content/browser/tracing/etw_system_event_consumer_win.h"
27 using base::trace_event::TraceLog
;
28 using base::trace_event::TraceOptions
;
29 using base::trace_event::CategoryFilter
;
35 base::LazyInstance
<TracingControllerImpl
>::Leaky g_controller
=
36 LAZY_INSTANCE_INITIALIZER
;
38 class FileTraceDataSink
: public TracingController::TraceDataSink
{
40 explicit FileTraceDataSink(const base::FilePath
& trace_file_path
,
41 const base::Closure
& callback
)
42 : file_path_(trace_file_path
),
43 completion_callback_(callback
),
46 void AddTraceChunk(const std::string
& chunk
) override
{
47 std::string tmp
= chunk
;
48 scoped_refptr
<base::RefCountedString
> chunk_ptr
=
49 base::RefCountedString::TakeString(&tmp
);
50 BrowserThread::PostTask(
54 &FileTraceDataSink::AddTraceChunkOnFileThread
, this, chunk_ptr
));
56 void SetSystemTrace(const std::string
& data
) override
{
59 void Close() override
{
60 BrowserThread::PostTask(
63 base::Bind(&FileTraceDataSink::CloseOnFileThread
, this));
67 ~FileTraceDataSink() override
{ DCHECK(file_
== NULL
); }
69 void AddTraceChunkOnFileThread(
70 const scoped_refptr
<base::RefCountedString
> chunk
) {
73 else if (!OpenFileIfNeededOnFileThread())
75 ignore_result(fwrite(chunk
->data().c_str(), strlen(chunk
->data().c_str()),
79 bool OpenFileIfNeededOnFileThread() {
82 file_
= base::OpenFile(file_path_
, "w");
84 LOG(ERROR
) << "Failed to open " << file_path_
.value();
87 const char preamble
[] = "{\"traceEvents\": [";
88 ignore_result(fwrite(preamble
, strlen(preamble
), 1, file_
));
92 void CloseOnFileThread() {
93 if (OpenFileIfNeededOnFileThread()) {
95 if (!system_trace_
.empty()) {
96 const char systemTraceEvents
[] = ",\"systemTraceEvents\": ";
97 ignore_result(fwrite(systemTraceEvents
, strlen(systemTraceEvents
),
99 ignore_result(fwrite(system_trace_
.c_str(),
100 strlen(system_trace_
.c_str()), 1, file_
));
103 base::CloseFile(file_
);
106 BrowserThread::PostTask(
109 base::Bind(&FileTraceDataSink::FinalizeOnUIThread
, this));
112 void FinalizeOnUIThread() { completion_callback_
.Run(); }
114 base::FilePath file_path_
;
115 base::Closure completion_callback_
;
117 std::string system_trace_
;
119 DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink
);
122 class StringTraceDataSink
: public TracingController::TraceDataSink
{
124 typedef base::Callback
<void(base::RefCountedString
*)> CompletionCallback
;
126 explicit StringTraceDataSink(CompletionCallback callback
)
127 : completion_callback_(callback
) {}
129 // TracingController::TraceDataSink implementation
130 void AddTraceChunk(const std::string
& chunk
) override
{
135 void SetSystemTrace(const std::string
& data
) override
{
136 system_trace_
= data
;
138 void Close() override
{
139 std::string result
= "{\"traceEvents\":[" + trace_
+ "]";
140 if (!system_trace_
.empty())
141 result
+= ",\"systemTraceEvents\": " + system_trace_
;
144 scoped_refptr
<base::RefCountedString
> str
=
145 base::RefCountedString::TakeString(&result
);
146 completion_callback_
.Run(str
.get());
150 ~StringTraceDataSink() override
{}
153 std::string system_trace_
;
154 CompletionCallback completion_callback_
;
156 DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink
);
161 TracingController
* TracingController::GetInstance() {
162 return TracingControllerImpl::GetInstance();
165 TracingControllerImpl::TracingControllerImpl()
166 : pending_disable_recording_ack_count_(0),
167 pending_capture_monitoring_snapshot_ack_count_(0),
168 pending_trace_log_status_ack_count_(0),
169 maximum_trace_buffer_usage_(0),
170 approximate_event_count_(0),
171 pending_memory_dump_ack_count_(0),
172 failed_memory_dump_count_(0),
173 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
174 // is specified in command line.
175 #if defined(OS_CHROMEOS) || defined(OS_WIN)
176 is_system_tracing_(false),
178 is_recording_(TraceLog::GetInstance()->IsEnabled()),
179 is_monitoring_(false) {
180 base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
183 TracingControllerImpl::~TracingControllerImpl() {
184 // This is a Leaky instance.
188 TracingControllerImpl
* TracingControllerImpl::GetInstance() {
189 return g_controller
.Pointer();
192 bool TracingControllerImpl::GetCategories(
193 const GetCategoriesDoneCallback
& callback
) {
194 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
196 // Known categories come back from child processes with the EndTracingAck
197 // message. So to get known categories, just begin and end tracing immediately
198 // afterwards. This will ping all the child processes for categories.
199 pending_get_categories_done_callback_
= callback
;
200 if (!EnableRecording(
201 CategoryFilter("*"), TraceOptions(), EnableRecordingDoneCallback())) {
202 pending_get_categories_done_callback_
.Reset();
206 bool ok
= DisableRecording(NULL
);
211 void TracingControllerImpl::SetEnabledOnFileThread(
212 const CategoryFilter
& category_filter
,
214 const TraceOptions
& trace_options
,
215 const base::Closure
& callback
) {
216 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
218 TraceLog::GetInstance()->SetEnabled(
219 category_filter
, static_cast<TraceLog::Mode
>(mode
), trace_options
);
220 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, callback
);
223 void TracingControllerImpl::SetDisabledOnFileThread(
224 const base::Closure
& callback
) {
225 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
227 TraceLog::GetInstance()->SetDisabled();
228 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, callback
);
231 bool TracingControllerImpl::EnableRecording(
232 const CategoryFilter
& category_filter
,
233 const TraceOptions
& trace_options
,
234 const EnableRecordingDoneCallback
& callback
) {
235 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
237 if (!can_enable_recording())
239 is_recording_
= true;
241 #if defined(OS_ANDROID)
242 if (pending_get_categories_done_callback_
.is_null())
243 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
246 trace_options_
= trace_options
;
248 if (trace_options
.enable_systrace
) {
249 #if defined(OS_CHROMEOS)
250 DCHECK(!is_system_tracing_
);
251 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
252 StartSystemTracing();
253 is_system_tracing_
= true;
254 #elif defined(OS_WIN)
255 DCHECK(!is_system_tracing_
);
257 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
262 base::Closure on_enable_recording_done_callback
=
263 base::Bind(&TracingControllerImpl::OnEnableRecordingDone
,
264 base::Unretained(this),
265 category_filter
, trace_options
, callback
);
266 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
267 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread
,
268 base::Unretained(this),
270 base::trace_event::TraceLog::RECORDING_MODE
,
272 on_enable_recording_done_callback
));
276 void TracingControllerImpl::OnEnableRecordingDone(
277 const CategoryFilter
& category_filter
,
278 const TraceOptions
& trace_options
,
279 const EnableRecordingDoneCallback
& callback
) {
280 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
282 // Notify all child processes.
283 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
284 it
!= trace_message_filters_
.end(); ++it
) {
285 it
->get()->SendBeginTracing(category_filter
, trace_options
);
288 if (!callback
.is_null())
292 bool TracingControllerImpl::DisableRecording(
293 const scoped_refptr
<TraceDataSink
>& trace_data_sink
) {
294 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
296 if (!can_disable_recording())
299 trace_data_sink_
= trace_data_sink
;
300 trace_options_
= TraceOptions();
301 // Disable local trace early to avoid traces during end-tracing process from
302 // interfering with the process.
303 base::Closure on_disable_recording_done_callback
= base::Bind(
304 &TracingControllerImpl::OnDisableRecordingDone
, base::Unretained(this));
305 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
306 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread
,
307 base::Unretained(this),
308 on_disable_recording_done_callback
));
312 void TracingControllerImpl::OnDisableRecordingDone() {
313 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
315 #if defined(OS_ANDROID)
316 if (pending_get_categories_done_callback_
.is_null())
317 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
320 // Count myself (local trace) in pending_disable_recording_ack_count_,
322 pending_disable_recording_ack_count_
= trace_message_filters_
.size() + 1;
323 pending_disable_recording_filters_
= trace_message_filters_
;
325 #if defined(OS_CHROMEOS) || defined(OS_WIN)
326 if (is_system_tracing_
) {
327 // Disable system tracing.
328 is_system_tracing_
= false;
329 ++pending_disable_recording_ack_count_
;
331 #if defined(OS_CHROMEOS)
332 scoped_refptr
<base::TaskRunner
> task_runner
=
333 BrowserThread::GetBlockingPool();
334 chromeos::DBusThreadManager::Get()
335 ->GetDebugDaemonClient()
336 ->RequestStopSystemTracing(
338 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked
,
339 base::Unretained(this)));
340 #elif defined(OS_WIN)
341 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
342 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked
,
343 base::Unretained(this)));
346 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
348 // Handle special case of zero child processes by immediately flushing the
349 // trace log. Once the flush has completed the caller will be notified that
350 // tracing has ended.
351 if (pending_disable_recording_ack_count_
== 1) {
352 // Flush asynchronously now, because we don't have any children to wait for.
353 TraceLog::GetInstance()->Flush(
354 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected
,
355 base::Unretained(this)),
359 // Notify all child processes.
360 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
361 it
!= trace_message_filters_
.end(); ++it
) {
362 it
->get()->SendEndTracing();
366 bool TracingControllerImpl::EnableMonitoring(
367 const CategoryFilter
& category_filter
,
368 const TraceOptions
& trace_options
,
369 const EnableMonitoringDoneCallback
& callback
) {
370 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
372 if (!can_enable_monitoring())
374 OnMonitoringStateChanged(true);
376 #if defined(OS_ANDROID)
377 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
380 trace_options_
= trace_options
;
382 base::Closure on_enable_monitoring_done_callback
=
383 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone
,
384 base::Unretained(this),
385 category_filter
, trace_options
, callback
);
386 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
387 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread
,
388 base::Unretained(this),
390 base::trace_event::TraceLog::MONITORING_MODE
,
392 on_enable_monitoring_done_callback
));
396 void TracingControllerImpl::OnEnableMonitoringDone(
397 const CategoryFilter
& category_filter
,
398 const TraceOptions
& trace_options
,
399 const EnableMonitoringDoneCallback
& callback
) {
400 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
402 // Notify all child processes.
403 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
404 it
!= trace_message_filters_
.end(); ++it
) {
405 it
->get()->SendEnableMonitoring(category_filter
, trace_options
);
408 if (!callback
.is_null())
412 bool TracingControllerImpl::DisableMonitoring(
413 const DisableMonitoringDoneCallback
& callback
) {
414 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
416 if (!can_disable_monitoring())
419 trace_options_
= TraceOptions();
420 base::Closure on_disable_monitoring_done_callback
=
421 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone
,
422 base::Unretained(this), callback
);
423 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
424 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread
,
425 base::Unretained(this),
426 on_disable_monitoring_done_callback
));
430 scoped_refptr
<TracingController::TraceDataSink
>
431 TracingController::CreateStringSink(
432 const base::Callback
<void(base::RefCountedString
*)>& callback
) {
433 return new StringTraceDataSink(callback
);
436 scoped_refptr
<TracingController::TraceDataSink
>
437 TracingController::CreateFileSink(const base::FilePath
& file_path
,
438 const base::Closure
& callback
) {
439 return new FileTraceDataSink(file_path
, callback
);
442 void TracingControllerImpl::OnDisableMonitoringDone(
443 const DisableMonitoringDoneCallback
& callback
) {
444 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
446 OnMonitoringStateChanged(false);
448 // Notify all child processes.
449 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
450 it
!= trace_message_filters_
.end(); ++it
) {
451 it
->get()->SendDisableMonitoring();
453 if (!callback
.is_null())
457 void TracingControllerImpl::GetMonitoringStatus(
459 CategoryFilter
* out_category_filter
,
460 TraceOptions
* out_trace_options
) {
461 *out_enabled
= is_monitoring_
;
462 *out_category_filter
= TraceLog::GetInstance()->GetCurrentCategoryFilter();
463 *out_trace_options
= trace_options_
;
466 bool TracingControllerImpl::CaptureMonitoringSnapshot(
467 const scoped_refptr
<TraceDataSink
>& monitoring_data_sink
) {
468 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
470 if (!can_disable_monitoring())
473 if (!monitoring_data_sink
.get())
476 monitoring_data_sink_
= monitoring_data_sink
;
478 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
480 pending_capture_monitoring_snapshot_ack_count_
=
481 trace_message_filters_
.size() + 1;
482 pending_capture_monitoring_filters_
= trace_message_filters_
;
484 // Handle special case of zero child processes by immediately flushing the
485 // trace log. Once the flush has completed the caller will be notified that
486 // the capture snapshot has ended.
487 if (pending_capture_monitoring_snapshot_ack_count_
== 1) {
488 // Flush asynchronously now, because we don't have any children to wait for.
489 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
490 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected
,
491 base::Unretained(this)));
494 // Notify all child processes.
495 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
496 it
!= trace_message_filters_
.end(); ++it
) {
497 it
->get()->SendCaptureMonitoringSnapshot();
500 #if defined(OS_ANDROID)
501 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
507 bool TracingControllerImpl::GetTraceBufferUsage(
508 const GetTraceBufferUsageCallback
& callback
) {
509 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
511 if (!can_get_trace_buffer_usage() || callback
.is_null())
514 pending_trace_buffer_usage_callback_
= callback
;
516 // Count myself in pending_trace_log_status_ack_count_, acked below.
517 pending_trace_log_status_ack_count_
= trace_message_filters_
.size() + 1;
518 pending_trace_log_status_filters_
= trace_message_filters_
;
519 maximum_trace_buffer_usage_
= 0;
520 approximate_event_count_
= 0;
522 base::trace_event::TraceLogStatus status
=
523 TraceLog::GetInstance()->GetStatus();
524 // Call OnTraceLogStatusReply unconditionally for the browser process.
525 // This will result in immediate execution of the callback if there are no
527 BrowserThread::PostTask(
528 BrowserThread::UI
, FROM_HERE
,
529 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply
,
530 base::Unretained(this), scoped_refptr
<TraceMessageFilter
>(),
533 // Notify all child processes.
534 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
535 it
!= trace_message_filters_
.end(); ++it
) {
536 it
->get()->SendGetTraceLogStatus();
541 bool TracingControllerImpl::SetWatchEvent(
542 const std::string
& category_name
,
543 const std::string
& event_name
,
544 const WatchEventCallback
& callback
) {
545 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
547 if (callback
.is_null())
550 watch_category_name_
= category_name
;
551 watch_event_name_
= event_name
;
552 watch_event_callback_
= callback
;
554 TraceLog::GetInstance()->SetWatchEvent(
555 category_name
, event_name
,
556 base::Bind(&TracingControllerImpl::OnWatchEventMatched
,
557 base::Unretained(this)));
559 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
560 it
!= trace_message_filters_
.end(); ++it
) {
561 it
->get()->SendSetWatchEvent(category_name
, event_name
);
566 bool TracingControllerImpl::CancelWatchEvent() {
567 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
569 if (!can_cancel_watch_event())
572 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
573 it
!= trace_message_filters_
.end(); ++it
) {
574 it
->get()->SendCancelWatchEvent();
577 watch_event_callback_
.Reset();
581 void TracingControllerImpl::AddTraceMessageFilter(
582 TraceMessageFilter
* trace_message_filter
) {
583 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
584 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
585 base::Bind(&TracingControllerImpl::AddTraceMessageFilter
,
586 base::Unretained(this),
587 make_scoped_refptr(trace_message_filter
)));
591 trace_message_filters_
.insert(trace_message_filter
);
592 if (can_cancel_watch_event()) {
593 trace_message_filter
->SendSetWatchEvent(watch_category_name_
,
596 if (can_disable_recording()) {
597 trace_message_filter
->SendBeginTracing(
598 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
599 TraceLog::GetInstance()->GetCurrentTraceOptions());
601 if (can_disable_monitoring()) {
602 trace_message_filter
->SendEnableMonitoring(
603 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
604 TraceLog::GetInstance()->GetCurrentTraceOptions());
608 void TracingControllerImpl::RemoveTraceMessageFilter(
609 TraceMessageFilter
* trace_message_filter
) {
610 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
611 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
612 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter
,
613 base::Unretained(this),
614 make_scoped_refptr(trace_message_filter
)));
618 // If a filter is removed while a response from that filter is pending then
619 // simulate the response. Otherwise the response count will be wrong and the
620 // completion callback will never be executed.
621 if (pending_disable_recording_ack_count_
> 0) {
622 TraceMessageFilterSet::const_iterator it
=
623 pending_disable_recording_filters_
.find(trace_message_filter
);
624 if (it
!= pending_disable_recording_filters_
.end()) {
625 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
626 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked
,
627 base::Unretained(this),
628 make_scoped_refptr(trace_message_filter
),
629 std::vector
<std::string
>()));
632 if (pending_capture_monitoring_snapshot_ack_count_
> 0) {
633 TraceMessageFilterSet::const_iterator it
=
634 pending_capture_monitoring_filters_
.find(trace_message_filter
);
635 if (it
!= pending_capture_monitoring_filters_
.end()) {
636 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
637 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked
,
638 base::Unretained(this),
639 make_scoped_refptr(trace_message_filter
)));
642 if (pending_trace_log_status_ack_count_
> 0) {
643 TraceMessageFilterSet::const_iterator it
=
644 pending_trace_log_status_filters_
.find(trace_message_filter
);
645 if (it
!= pending_trace_log_status_filters_
.end()) {
646 BrowserThread::PostTask(
647 BrowserThread::UI
, FROM_HERE
,
648 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply
,
649 base::Unretained(this),
650 make_scoped_refptr(trace_message_filter
),
651 base::trace_event::TraceLogStatus()));
654 if (pending_memory_dump_ack_count_
> 0) {
655 TraceMessageFilterSet::const_iterator it
=
656 pending_memory_dump_filters_
.find(trace_message_filter
);
657 if (it
!= pending_memory_dump_filters_
.end()) {
658 BrowserThread::PostTask(
659 BrowserThread::UI
, FROM_HERE
,
660 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse
,
661 base::Unretained(this),
662 make_scoped_refptr(trace_message_filter
),
663 pending_memory_dump_guid_
, false /* success */));
666 trace_message_filters_
.erase(trace_message_filter
);
669 void TracingControllerImpl::OnDisableRecordingAcked(
670 TraceMessageFilter
* trace_message_filter
,
671 const std::vector
<std::string
>& known_category_groups
) {
672 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
673 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
674 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked
,
675 base::Unretained(this),
676 make_scoped_refptr(trace_message_filter
),
677 known_category_groups
));
681 // Merge known_category_groups with known_category_groups_
682 known_category_groups_
.insert(known_category_groups
.begin(),
683 known_category_groups
.end());
685 if (pending_disable_recording_ack_count_
== 0)
688 if (trace_message_filter
&&
689 !pending_disable_recording_filters_
.erase(trace_message_filter
)) {
690 // The response from the specified message filter has already been received.
694 if (--pending_disable_recording_ack_count_
== 1) {
695 // All acks from subprocesses have been received. Now flush the local trace.
696 // During or after this call, our OnLocalTraceDataCollected will be
697 // called with the last of the local trace data.
698 TraceLog::GetInstance()->Flush(
699 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected
,
700 base::Unretained(this)),
705 if (pending_disable_recording_ack_count_
!= 0)
708 // All acks (including from the subprocesses and the local trace) have been
710 is_recording_
= false;
712 // Trigger callback if one is set.
713 if (!pending_get_categories_done_callback_
.is_null()) {
714 pending_get_categories_done_callback_
.Run(known_category_groups_
);
715 pending_get_categories_done_callback_
.Reset();
716 } else if (trace_data_sink_
.get()) {
717 trace_data_sink_
->Close();
718 trace_data_sink_
= NULL
;
722 #if defined(OS_CHROMEOS) || defined(OS_WIN)
723 void TracingControllerImpl::OnEndSystemTracingAcked(
724 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
) {
725 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
727 if (trace_data_sink_
.get()) {
729 // The Windows kernel events are kept into a JSon format stored as string
730 // and must not be escaped.
731 std::string json_string
= events_str_ptr
->data();
733 std::string json_string
=
734 base::GetQuotedJSONString(events_str_ptr
->data());
736 trace_data_sink_
->SetSystemTrace(json_string
);
738 DCHECK(!is_system_tracing_
);
739 std::vector
<std::string
> category_groups
;
740 OnDisableRecordingAcked(NULL
, category_groups
);
744 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
745 TraceMessageFilter
* trace_message_filter
) {
746 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
747 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
748 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked
,
749 base::Unretained(this),
750 make_scoped_refptr(trace_message_filter
)));
754 if (pending_capture_monitoring_snapshot_ack_count_
== 0)
757 if (trace_message_filter
&&
758 !pending_capture_monitoring_filters_
.erase(trace_message_filter
)) {
759 // The response from the specified message filter has already been received.
763 if (--pending_capture_monitoring_snapshot_ack_count_
== 1) {
764 // All acks from subprocesses have been received. Now flush the local trace.
765 // During or after this call, our OnLocalMonitoringTraceDataCollected
766 // will be called with the last of the local trace data.
767 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
768 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected
,
769 base::Unretained(this)));
773 if (pending_capture_monitoring_snapshot_ack_count_
!= 0)
776 if (monitoring_data_sink_
.get()) {
777 monitoring_data_sink_
->Close();
778 monitoring_data_sink_
= NULL
;
782 void TracingControllerImpl::OnTraceDataCollected(
783 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
) {
784 // OnTraceDataCollected may be called from any browser thread, either by the
785 // local event trace system or from child processes via TraceMessageFilter.
786 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
787 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
788 base::Bind(&TracingControllerImpl::OnTraceDataCollected
,
789 base::Unretained(this), events_str_ptr
));
793 if (trace_data_sink_
.get())
794 trace_data_sink_
->AddTraceChunk(events_str_ptr
->data());
797 void TracingControllerImpl::OnMonitoringTraceDataCollected(
798 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
) {
799 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
800 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
801 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected
,
802 base::Unretained(this), events_str_ptr
));
806 if (monitoring_data_sink_
.get())
807 monitoring_data_sink_
->AddTraceChunk(events_str_ptr
->data());
810 void TracingControllerImpl::OnLocalTraceDataCollected(
811 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
,
812 bool has_more_events
) {
813 if (events_str_ptr
->data().size())
814 OnTraceDataCollected(events_str_ptr
);
819 // Simulate an DisableRecordingAcked for the local trace.
820 std::vector
<std::string
> category_groups
;
821 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups
);
822 OnDisableRecordingAcked(NULL
, category_groups
);
825 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
826 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
,
827 bool has_more_events
) {
828 if (events_str_ptr
->data().size())
829 OnMonitoringTraceDataCollected(events_str_ptr
);
834 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
835 OnCaptureMonitoringSnapshotAcked(NULL
);
838 void TracingControllerImpl::OnTraceLogStatusReply(
839 TraceMessageFilter
* trace_message_filter
,
840 const base::trace_event::TraceLogStatus
& status
) {
841 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
842 BrowserThread::PostTask(
843 BrowserThread::UI
, FROM_HERE
,
844 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply
,
845 base::Unretained(this),
846 make_scoped_refptr(trace_message_filter
), status
));
850 if (pending_trace_log_status_ack_count_
== 0)
853 if (trace_message_filter
&&
854 !pending_trace_log_status_filters_
.erase(trace_message_filter
)) {
855 // The response from the specified message filter has already been received.
859 float percent_full
= static_cast<float>(
860 static_cast<double>(status
.event_count
) / status
.event_capacity
);
861 maximum_trace_buffer_usage_
=
862 std::max(maximum_trace_buffer_usage_
, percent_full
);
863 approximate_event_count_
+= status
.event_count
;
865 if (--pending_trace_log_status_ack_count_
== 0) {
866 // Trigger callback if one is set.
867 pending_trace_buffer_usage_callback_
.Run(maximum_trace_buffer_usage_
,
868 approximate_event_count_
);
869 pending_trace_buffer_usage_callback_
.Reset();
873 void TracingControllerImpl::OnWatchEventMatched() {
874 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
875 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
876 base::Bind(&TracingControllerImpl::OnWatchEventMatched
,
877 base::Unretained(this)));
881 if (!watch_event_callback_
.is_null())
882 watch_event_callback_
.Run();
885 void TracingControllerImpl::RegisterTracingUI(TracingUI
* tracing_ui
) {
886 DCHECK(tracing_uis_
.find(tracing_ui
) == tracing_uis_
.end());
887 tracing_uis_
.insert(tracing_ui
);
890 void TracingControllerImpl::UnregisterTracingUI(TracingUI
* tracing_ui
) {
891 std::set
<TracingUI
*>::iterator it
= tracing_uis_
.find(tracing_ui
);
892 DCHECK(it
!= tracing_uis_
.end());
893 tracing_uis_
.erase(it
);
896 void TracingControllerImpl::RequestGlobalMemoryDump(
897 const base::trace_event::MemoryDumpRequestArgs
& args
,
898 const base::trace_event::MemoryDumpCallback
& callback
) {
899 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
900 BrowserThread::PostTask(
901 BrowserThread::UI
, FROM_HERE
,
902 base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump
,
903 base::Unretained(this), args
, callback
));
906 // Abort if another dump is already in progress.
907 if (pending_memory_dump_guid_
) {
908 DVLOG(1) << "Requested memory dump " << args
.dump_guid
909 << " while waiting for " << pending_memory_dump_guid_
;
910 if (!callback
.is_null())
911 callback
.Run(args
.dump_guid
, false /* success */);
915 // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
916 // OnBrowserProcessMemoryDumpDone().
917 pending_memory_dump_ack_count_
= trace_message_filters_
.size() + 1;
918 pending_memory_dump_filters_
.clear();
919 failed_memory_dump_count_
= 0;
921 MemoryDumpManagerDelegate::CreateProcessDump(
922 args
, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone
,
923 base::Unretained(this)));
925 // If there are no child processes we are just done.
926 if (pending_memory_dump_ack_count_
== 1) {
927 if (!callback
.is_null())
928 callback
.Run(args
.dump_guid
, true /* success */);
932 pending_memory_dump_guid_
= args
.dump_guid
;
933 pending_memory_dump_callback_
= callback
;
934 pending_memory_dump_filters_
= trace_message_filters_
;
936 for (const scoped_refptr
<TraceMessageFilter
>& tmf
: trace_message_filters_
)
937 tmf
->SendProcessMemoryDumpRequest(args
);
940 bool TracingControllerImpl::IsCoordinatorProcess() const {
944 void TracingControllerImpl::OnProcessMemoryDumpResponse(
945 TraceMessageFilter
* trace_message_filter
,
948 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
949 BrowserThread::PostTask(
950 BrowserThread::UI
, FROM_HERE
,
951 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse
,
952 base::Unretained(this),
953 make_scoped_refptr(trace_message_filter
), dump_guid
,
958 TraceMessageFilterSet::iterator it
=
959 pending_memory_dump_filters_
.find(trace_message_filter
);
961 if (pending_memory_dump_guid_
!= dump_guid
||
962 it
== pending_memory_dump_filters_
.end()) {
963 DLOG(WARNING
) << "Received unexpected memory dump response: " << dump_guid
;
967 DCHECK_GT(pending_memory_dump_ack_count_
, 0);
968 --pending_memory_dump_ack_count_
;
969 pending_memory_dump_filters_
.erase(it
);
971 ++failed_memory_dump_count_
;
972 DLOG(WARNING
) << "Global memory dump failed because of NACK from child "
973 << trace_message_filter
->peer_pid();
975 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
978 void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64 dump_guid
,
980 DCHECK_GT(pending_memory_dump_ack_count_
, 0);
981 --pending_memory_dump_ack_count_
;
982 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
985 void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
986 if (pending_memory_dump_ack_count_
> 0)
989 DCHECK_NE(0u, pending_memory_dump_guid_
);
990 const bool global_success
= failed_memory_dump_count_
== 0;
991 if (!pending_memory_dump_callback_
.is_null()) {
992 pending_memory_dump_callback_
.Run(pending_memory_dump_guid_
,
994 pending_memory_dump_callback_
.Reset();
996 pending_memory_dump_guid_
= 0;
999 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring
) {
1000 if (is_monitoring_
== is_monitoring
)
1003 is_monitoring_
= is_monitoring
;
1004 #if !defined(OS_ANDROID)
1005 for (std::set
<TracingUI
*>::iterator it
= tracing_uis_
.begin();
1006 it
!= tracing_uis_
.end(); it
++) {
1007 (*it
)->OnMonitoringStateChanged(is_monitoring
);
1012 } // namespace content