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/file_tracing_provider_impl.h"
13 #include "content/browser/tracing/trace_message_filter.h"
14 #include "content/browser/tracing/tracing_ui.h"
15 #include "content/common/child_process_messages.h"
16 #include "content/public/browser/browser_message_filter.h"
17 #include "content/public/common/content_switches.h"
19 #if defined(OS_CHROMEOS)
20 #include "chromeos/dbus/dbus_thread_manager.h"
21 #include "chromeos/dbus/debug_daemon_client.h"
25 #include "content/browser/tracing/etw_system_event_consumer_win.h"
28 using base::trace_event::TraceLog
;
29 using base::trace_event::TraceConfig
;
35 base::LazyInstance
<TracingControllerImpl
>::Leaky g_controller
=
36 LAZY_INSTANCE_INITIALIZER
;
40 TracingController
* TracingController::GetInstance() {
41 return TracingControllerImpl::GetInstance();
44 TracingControllerImpl::TracingControllerImpl()
45 : pending_disable_recording_ack_count_(0),
46 pending_capture_monitoring_snapshot_ack_count_(0),
47 pending_trace_log_status_ack_count_(0),
48 maximum_trace_buffer_usage_(0),
49 approximate_event_count_(0),
50 pending_memory_dump_ack_count_(0),
51 failed_memory_dump_count_(0),
52 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
53 // is specified in command line.
54 #if defined(OS_CHROMEOS) || defined(OS_WIN)
55 is_system_tracing_(false),
57 is_recording_(TraceLog::GetInstance()->IsEnabled()),
58 is_monitoring_(false) {
59 base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
61 // Deliberately leaked, like this class.
62 base::FileTracing::SetProvider(new FileTracingProviderImpl
);
65 TracingControllerImpl::~TracingControllerImpl() {
66 // This is a Leaky instance.
70 TracingControllerImpl
* TracingControllerImpl::GetInstance() {
71 return g_controller
.Pointer();
74 bool TracingControllerImpl::GetCategories(
75 const GetCategoriesDoneCallback
& callback
) {
76 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
78 // Known categories come back from child processes with the EndTracingAck
79 // message. So to get known categories, just begin and end tracing immediately
80 // afterwards. This will ping all the child processes for categories.
81 pending_get_categories_done_callback_
= callback
;
82 if (!EnableRecording(TraceConfig("*", ""), EnableRecordingDoneCallback())) {
83 pending_get_categories_done_callback_
.Reset();
87 bool ok
= DisableRecording(NULL
);
92 void TracingControllerImpl::SetEnabledOnFileThread(
93 const TraceConfig
& trace_config
,
95 const base::Closure
& callback
) {
96 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
98 TraceLog::GetInstance()->SetEnabled(
99 trace_config
, static_cast<TraceLog::Mode
>(mode
));
100 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, callback
);
103 void TracingControllerImpl::SetDisabledOnFileThread(
104 const base::Closure
& callback
) {
105 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
107 TraceLog::GetInstance()->SetDisabled();
108 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, callback
);
111 bool TracingControllerImpl::EnableRecording(
112 const TraceConfig
& trace_config
,
113 const EnableRecordingDoneCallback
& callback
) {
114 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
116 if (!can_enable_recording())
118 is_recording_
= true;
120 #if defined(OS_ANDROID)
121 if (pending_get_categories_done_callback_
.is_null())
122 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
125 if (trace_config
.IsSystraceEnabled()) {
126 #if defined(OS_CHROMEOS)
127 DCHECK(!is_system_tracing_
);
128 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
129 StartSystemTracing();
130 is_system_tracing_
= true;
131 #elif defined(OS_WIN)
132 DCHECK(!is_system_tracing_
);
134 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
139 base::Closure on_enable_recording_done_callback
=
140 base::Bind(&TracingControllerImpl::OnEnableRecordingDone
,
141 base::Unretained(this),
142 trace_config
, callback
);
143 if (!BrowserThread::PostTask(
144 BrowserThread::FILE, FROM_HERE
,
145 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread
,
146 base::Unretained(this), trace_config
,
147 base::trace_event::TraceLog::RECORDING_MODE
,
148 on_enable_recording_done_callback
))) {
149 // BrowserThread::PostTask fails if the threads haven't been created yet,
150 // so it should be safe to just use TraceLog::SetEnabled directly.
151 base::trace_event::TraceLog::GetInstance()->SetEnabled(
152 trace_config
, base::trace_event::TraceLog::RECORDING_MODE
);
153 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
154 on_enable_recording_done_callback
);
160 void TracingControllerImpl::OnEnableRecordingDone(
161 const TraceConfig
& trace_config
,
162 const EnableRecordingDoneCallback
& callback
) {
163 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
165 // Notify all child processes.
166 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
167 it
!= trace_message_filters_
.end(); ++it
) {
168 it
->get()->SendBeginTracing(trace_config
);
171 if (!callback
.is_null())
175 bool TracingControllerImpl::DisableRecording(
176 const scoped_refptr
<TraceDataSink
>& trace_data_sink
) {
177 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
179 if (!can_disable_recording())
182 trace_data_sink_
= trace_data_sink
;
183 // Disable local trace early to avoid traces during end-tracing process from
184 // interfering with the process.
185 base::Closure on_disable_recording_done_callback
= base::Bind(
186 &TracingControllerImpl::OnDisableRecordingDone
, base::Unretained(this));
187 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
188 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread
,
189 base::Unretained(this),
190 on_disable_recording_done_callback
));
194 void TracingControllerImpl::OnDisableRecordingDone() {
195 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
197 #if defined(OS_ANDROID)
198 if (pending_get_categories_done_callback_
.is_null())
199 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
202 // Count myself (local trace) in pending_disable_recording_ack_count_,
204 pending_disable_recording_ack_count_
= trace_message_filters_
.size() + 1;
205 pending_disable_recording_filters_
= trace_message_filters_
;
207 #if defined(OS_CHROMEOS) || defined(OS_WIN)
208 if (is_system_tracing_
) {
209 // Disable system tracing.
210 is_system_tracing_
= false;
211 ++pending_disable_recording_ack_count_
;
213 #if defined(OS_CHROMEOS)
214 scoped_refptr
<base::TaskRunner
> task_runner
=
215 BrowserThread::GetBlockingPool();
216 chromeos::DBusThreadManager::Get()
217 ->GetDebugDaemonClient()
218 ->RequestStopSystemTracing(
220 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked
,
221 base::Unretained(this)));
222 #elif defined(OS_WIN)
223 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
224 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked
,
225 base::Unretained(this)));
228 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
230 // Handle special case of zero child processes by immediately flushing the
231 // trace log. Once the flush has completed the caller will be notified that
232 // tracing has ended.
233 if (pending_disable_recording_ack_count_
== 1) {
234 // Flush/cancel asynchronously now, because we don't have any children to
236 if (trace_data_sink_
) {
237 TraceLog::GetInstance()->Flush(
238 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected
,
239 base::Unretained(this)),
242 TraceLog::GetInstance()->CancelTracing(
243 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected
,
244 base::Unretained(this)));
248 // Notify all child processes.
249 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
250 it
!= trace_message_filters_
.end(); ++it
) {
251 if (trace_data_sink_
)
252 it
->get()->SendEndTracing();
254 it
->get()->SendCancelTracing();
258 bool TracingControllerImpl::EnableMonitoring(
259 const TraceConfig
& trace_config
,
260 const EnableMonitoringDoneCallback
& callback
) {
261 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
263 if (!can_enable_monitoring())
265 OnMonitoringStateChanged(true);
267 #if defined(OS_ANDROID)
268 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
271 base::Closure on_enable_monitoring_done_callback
=
272 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone
,
273 base::Unretained(this),
274 trace_config
, callback
);
275 if (!BrowserThread::PostTask(
276 BrowserThread::FILE, FROM_HERE
,
277 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread
,
278 base::Unretained(this), trace_config
,
279 base::trace_event::TraceLog::MONITORING_MODE
,
280 on_enable_monitoring_done_callback
))) {
281 // BrowserThread::PostTask fails if the threads haven't been created yet,
282 // so it should be safe to just use TraceLog::SetEnabled directly.
283 base::trace_event::TraceLog::GetInstance()->SetEnabled(
284 trace_config
, base::trace_event::TraceLog::MONITORING_MODE
);
285 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
286 on_enable_monitoring_done_callback
);
291 void TracingControllerImpl::OnEnableMonitoringDone(
292 const TraceConfig
& trace_config
,
293 const EnableMonitoringDoneCallback
& callback
) {
294 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
296 // Notify all child processes.
297 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
298 it
!= trace_message_filters_
.end(); ++it
) {
299 it
->get()->SendEnableMonitoring(trace_config
);
302 if (!callback
.is_null())
306 bool TracingControllerImpl::DisableMonitoring(
307 const DisableMonitoringDoneCallback
& callback
) {
308 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
310 if (!can_disable_monitoring())
313 base::Closure on_disable_monitoring_done_callback
=
314 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone
,
315 base::Unretained(this), callback
);
316 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
317 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread
,
318 base::Unretained(this),
319 on_disable_monitoring_done_callback
));
323 void TracingControllerImpl::OnDisableMonitoringDone(
324 const DisableMonitoringDoneCallback
& callback
) {
325 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
327 OnMonitoringStateChanged(false);
329 // Notify all child processes.
330 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
331 it
!= trace_message_filters_
.end(); ++it
) {
332 it
->get()->SendDisableMonitoring();
334 if (!callback
.is_null())
338 void TracingControllerImpl::GetMonitoringStatus(
340 TraceConfig
* out_trace_config
) {
341 *out_enabled
= is_monitoring_
;
342 *out_trace_config
= TraceLog::GetInstance()->GetCurrentTraceConfig();
345 bool TracingControllerImpl::CaptureMonitoringSnapshot(
346 const scoped_refptr
<TraceDataSink
>& monitoring_data_sink
) {
347 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
349 if (!can_disable_monitoring())
352 if (!monitoring_data_sink
.get())
355 monitoring_data_sink_
= monitoring_data_sink
;
357 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
359 pending_capture_monitoring_snapshot_ack_count_
=
360 trace_message_filters_
.size() + 1;
361 pending_capture_monitoring_filters_
= trace_message_filters_
;
363 // Handle special case of zero child processes by immediately flushing the
364 // trace log. Once the flush has completed the caller will be notified that
365 // the capture snapshot has ended.
366 if (pending_capture_monitoring_snapshot_ack_count_
== 1) {
367 // Flush asynchronously now, because we don't have any children to wait for.
368 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
369 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected
,
370 base::Unretained(this)));
373 // Notify all child processes.
374 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
375 it
!= trace_message_filters_
.end(); ++it
) {
376 it
->get()->SendCaptureMonitoringSnapshot();
379 #if defined(OS_ANDROID)
380 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
386 bool TracingControllerImpl::GetTraceBufferUsage(
387 const GetTraceBufferUsageCallback
& callback
) {
388 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
390 if (!can_get_trace_buffer_usage() || callback
.is_null())
393 pending_trace_buffer_usage_callback_
= callback
;
395 // Count myself in pending_trace_log_status_ack_count_, acked below.
396 pending_trace_log_status_ack_count_
= trace_message_filters_
.size() + 1;
397 pending_trace_log_status_filters_
= trace_message_filters_
;
398 maximum_trace_buffer_usage_
= 0;
399 approximate_event_count_
= 0;
401 base::trace_event::TraceLogStatus status
=
402 TraceLog::GetInstance()->GetStatus();
403 // Call OnTraceLogStatusReply unconditionally for the browser process.
404 // This will result in immediate execution of the callback if there are no
406 BrowserThread::PostTask(
407 BrowserThread::UI
, FROM_HERE
,
408 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply
,
409 base::Unretained(this), scoped_refptr
<TraceMessageFilter
>(),
412 // Notify all child processes.
413 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
414 it
!= trace_message_filters_
.end(); ++it
) {
415 it
->get()->SendGetTraceLogStatus();
420 bool TracingControllerImpl::SetWatchEvent(
421 const std::string
& category_name
,
422 const std::string
& event_name
,
423 const WatchEventCallback
& callback
) {
424 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
426 if (callback
.is_null())
429 watch_category_name_
= category_name
;
430 watch_event_name_
= event_name
;
431 watch_event_callback_
= callback
;
433 TraceLog::GetInstance()->SetWatchEvent(
434 category_name
, event_name
,
435 base::Bind(&TracingControllerImpl::OnWatchEventMatched
,
436 base::Unretained(this)));
438 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
439 it
!= trace_message_filters_
.end(); ++it
) {
440 it
->get()->SendSetWatchEvent(category_name
, event_name
);
445 bool TracingControllerImpl::CancelWatchEvent() {
446 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
448 if (!can_cancel_watch_event())
451 for (TraceMessageFilterSet::iterator it
= trace_message_filters_
.begin();
452 it
!= trace_message_filters_
.end(); ++it
) {
453 it
->get()->SendCancelWatchEvent();
456 watch_event_callback_
.Reset();
460 bool TracingControllerImpl::IsRecording() const {
461 return is_recording_
;
464 void TracingControllerImpl::AddTraceMessageFilter(
465 TraceMessageFilter
* trace_message_filter
) {
466 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
467 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
468 base::Bind(&TracingControllerImpl::AddTraceMessageFilter
,
469 base::Unretained(this),
470 make_scoped_refptr(trace_message_filter
)));
474 trace_message_filters_
.insert(trace_message_filter
);
475 if (can_cancel_watch_event()) {
476 trace_message_filter
->SendSetWatchEvent(watch_category_name_
,
479 if (can_disable_recording()) {
480 trace_message_filter
->SendBeginTracing(
481 TraceLog::GetInstance()->GetCurrentTraceConfig());
483 if (can_disable_monitoring()) {
484 trace_message_filter
->SendEnableMonitoring(
485 TraceLog::GetInstance()->GetCurrentTraceConfig());
489 void TracingControllerImpl::RemoveTraceMessageFilter(
490 TraceMessageFilter
* trace_message_filter
) {
491 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
492 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
493 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter
,
494 base::Unretained(this),
495 make_scoped_refptr(trace_message_filter
)));
499 // If a filter is removed while a response from that filter is pending then
500 // simulate the response. Otherwise the response count will be wrong and the
501 // completion callback will never be executed.
502 if (pending_disable_recording_ack_count_
> 0) {
503 TraceMessageFilterSet::const_iterator it
=
504 pending_disable_recording_filters_
.find(trace_message_filter
);
505 if (it
!= pending_disable_recording_filters_
.end()) {
506 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
507 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked
,
508 base::Unretained(this),
509 make_scoped_refptr(trace_message_filter
),
510 std::vector
<std::string
>()));
513 if (pending_capture_monitoring_snapshot_ack_count_
> 0) {
514 TraceMessageFilterSet::const_iterator it
=
515 pending_capture_monitoring_filters_
.find(trace_message_filter
);
516 if (it
!= pending_capture_monitoring_filters_
.end()) {
517 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
518 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked
,
519 base::Unretained(this),
520 make_scoped_refptr(trace_message_filter
)));
523 if (pending_trace_log_status_ack_count_
> 0) {
524 TraceMessageFilterSet::const_iterator it
=
525 pending_trace_log_status_filters_
.find(trace_message_filter
);
526 if (it
!= pending_trace_log_status_filters_
.end()) {
527 BrowserThread::PostTask(
528 BrowserThread::UI
, FROM_HERE
,
529 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply
,
530 base::Unretained(this),
531 make_scoped_refptr(trace_message_filter
),
532 base::trace_event::TraceLogStatus()));
535 if (pending_memory_dump_ack_count_
> 0) {
536 TraceMessageFilterSet::const_iterator it
=
537 pending_memory_dump_filters_
.find(trace_message_filter
);
538 if (it
!= pending_memory_dump_filters_
.end()) {
539 BrowserThread::PostTask(
540 BrowserThread::UI
, FROM_HERE
,
541 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse
,
542 base::Unretained(this),
543 make_scoped_refptr(trace_message_filter
),
544 pending_memory_dump_guid_
, false /* success */));
547 trace_message_filters_
.erase(trace_message_filter
);
550 void TracingControllerImpl::OnDisableRecordingAcked(
551 TraceMessageFilter
* trace_message_filter
,
552 const std::vector
<std::string
>& known_category_groups
) {
553 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
554 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
555 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked
,
556 base::Unretained(this),
557 make_scoped_refptr(trace_message_filter
),
558 known_category_groups
));
562 // Merge known_category_groups with known_category_groups_
563 known_category_groups_
.insert(known_category_groups
.begin(),
564 known_category_groups
.end());
566 if (pending_disable_recording_ack_count_
== 0)
569 if (trace_message_filter
&&
570 !pending_disable_recording_filters_
.erase(trace_message_filter
)) {
571 // The response from the specified message filter has already been received.
575 if (--pending_disable_recording_ack_count_
== 1) {
576 // All acks from subprocesses have been received. Now flush the local trace.
577 // During or after this call, our OnLocalTraceDataCollected will be
578 // called with the last of the local trace data.
579 if (trace_data_sink_
) {
580 TraceLog::GetInstance()->Flush(
581 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected
,
582 base::Unretained(this)),
585 TraceLog::GetInstance()->CancelTracing(
586 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected
,
587 base::Unretained(this)));
592 if (pending_disable_recording_ack_count_
!= 0)
595 // All acks (including from the subprocesses and the local trace) have been
597 is_recording_
= false;
599 // Trigger callback if one is set.
600 if (!pending_get_categories_done_callback_
.is_null()) {
601 pending_get_categories_done_callback_
.Run(known_category_groups_
);
602 pending_get_categories_done_callback_
.Reset();
603 } else if (trace_data_sink_
.get()) {
604 trace_data_sink_
->Close();
605 trace_data_sink_
= NULL
;
609 #if defined(OS_CHROMEOS) || defined(OS_WIN)
610 void TracingControllerImpl::OnEndSystemTracingAcked(
611 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
) {
612 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
614 if (trace_data_sink_
.get()) {
616 // The Windows kernel events are kept into a JSon format stored as string
617 // and must not be escaped.
618 std::string json_string
= events_str_ptr
->data();
620 std::string json_string
=
621 base::GetQuotedJSONString(events_str_ptr
->data());
623 trace_data_sink_
->SetSystemTrace(json_string
);
625 DCHECK(!is_system_tracing_
);
626 std::vector
<std::string
> category_groups
;
627 OnDisableRecordingAcked(NULL
, category_groups
);
631 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
632 TraceMessageFilter
* trace_message_filter
) {
633 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
634 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
635 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked
,
636 base::Unretained(this),
637 make_scoped_refptr(trace_message_filter
)));
641 if (pending_capture_monitoring_snapshot_ack_count_
== 0)
644 if (trace_message_filter
&&
645 !pending_capture_monitoring_filters_
.erase(trace_message_filter
)) {
646 // The response from the specified message filter has already been received.
650 if (--pending_capture_monitoring_snapshot_ack_count_
== 1) {
651 // All acks from subprocesses have been received. Now flush the local trace.
652 // During or after this call, our OnLocalMonitoringTraceDataCollected
653 // will be called with the last of the local trace data.
654 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
655 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected
,
656 base::Unretained(this)));
660 if (pending_capture_monitoring_snapshot_ack_count_
!= 0)
663 if (monitoring_data_sink_
.get()) {
664 monitoring_data_sink_
->Close();
665 monitoring_data_sink_
= NULL
;
669 void TracingControllerImpl::OnTraceDataCollected(
670 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
) {
671 // OnTraceDataCollected may be called from any browser thread, either by the
672 // local event trace system or from child processes via TraceMessageFilter.
673 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
674 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
675 base::Bind(&TracingControllerImpl::OnTraceDataCollected
,
676 base::Unretained(this), events_str_ptr
));
680 if (trace_data_sink_
.get())
681 trace_data_sink_
->AddTraceChunk(events_str_ptr
->data());
684 void TracingControllerImpl::OnMonitoringTraceDataCollected(
685 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
) {
686 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
687 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
688 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected
,
689 base::Unretained(this), events_str_ptr
));
693 if (monitoring_data_sink_
.get())
694 monitoring_data_sink_
->AddTraceChunk(events_str_ptr
->data());
697 void TracingControllerImpl::OnLocalTraceDataCollected(
698 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
,
699 bool has_more_events
) {
700 if (events_str_ptr
->data().size())
701 OnTraceDataCollected(events_str_ptr
);
706 // Simulate an DisableRecordingAcked for the local trace.
707 std::vector
<std::string
> category_groups
;
708 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups
);
709 OnDisableRecordingAcked(NULL
, category_groups
);
712 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
713 const scoped_refptr
<base::RefCountedString
>& events_str_ptr
,
714 bool has_more_events
) {
715 if (events_str_ptr
->data().size())
716 OnMonitoringTraceDataCollected(events_str_ptr
);
721 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
722 OnCaptureMonitoringSnapshotAcked(NULL
);
725 void TracingControllerImpl::OnTraceLogStatusReply(
726 TraceMessageFilter
* trace_message_filter
,
727 const base::trace_event::TraceLogStatus
& status
) {
728 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
729 BrowserThread::PostTask(
730 BrowserThread::UI
, FROM_HERE
,
731 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply
,
732 base::Unretained(this),
733 make_scoped_refptr(trace_message_filter
), status
));
737 if (pending_trace_log_status_ack_count_
== 0)
740 if (trace_message_filter
&&
741 !pending_trace_log_status_filters_
.erase(trace_message_filter
)) {
742 // The response from the specified message filter has already been received.
746 float percent_full
= static_cast<float>(
747 static_cast<double>(status
.event_count
) / status
.event_capacity
);
748 maximum_trace_buffer_usage_
=
749 std::max(maximum_trace_buffer_usage_
, percent_full
);
750 approximate_event_count_
+= status
.event_count
;
752 if (--pending_trace_log_status_ack_count_
== 0) {
753 // Trigger callback if one is set.
754 pending_trace_buffer_usage_callback_
.Run(maximum_trace_buffer_usage_
,
755 approximate_event_count_
);
756 pending_trace_buffer_usage_callback_
.Reset();
760 void TracingControllerImpl::OnWatchEventMatched() {
761 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
762 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
763 base::Bind(&TracingControllerImpl::OnWatchEventMatched
,
764 base::Unretained(this)));
768 if (!watch_event_callback_
.is_null())
769 watch_event_callback_
.Run();
772 void TracingControllerImpl::RegisterTracingUI(TracingUI
* tracing_ui
) {
773 DCHECK(tracing_uis_
.find(tracing_ui
) == tracing_uis_
.end());
774 tracing_uis_
.insert(tracing_ui
);
777 void TracingControllerImpl::UnregisterTracingUI(TracingUI
* tracing_ui
) {
778 std::set
<TracingUI
*>::iterator it
= tracing_uis_
.find(tracing_ui
);
779 DCHECK(it
!= tracing_uis_
.end());
780 tracing_uis_
.erase(it
);
783 void TracingControllerImpl::RequestGlobalMemoryDump(
784 const base::trace_event::MemoryDumpRequestArgs
& args
,
785 const base::trace_event::MemoryDumpCallback
& callback
) {
786 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
787 BrowserThread::PostTask(
788 BrowserThread::UI
, FROM_HERE
,
789 base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump
,
790 base::Unretained(this), args
, callback
));
793 // Abort if another dump is already in progress.
794 if (pending_memory_dump_guid_
) {
795 DVLOG(1) << "Requested memory dump " << args
.dump_guid
796 << " while waiting for " << pending_memory_dump_guid_
;
797 if (!callback
.is_null())
798 callback
.Run(args
.dump_guid
, false /* success */);
802 // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
803 // OnBrowserProcessMemoryDumpDone().
804 pending_memory_dump_ack_count_
= trace_message_filters_
.size() + 1;
805 pending_memory_dump_filters_
.clear();
806 pending_memory_dump_guid_
= args
.dump_guid
;
807 pending_memory_dump_callback_
= callback
;
808 failed_memory_dump_count_
= 0;
810 MemoryDumpManagerDelegate::CreateProcessDump(
811 args
, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone
,
812 base::Unretained(this)));
814 // If there are no child processes we are just done.
815 if (pending_memory_dump_ack_count_
== 1)
818 pending_memory_dump_filters_
= trace_message_filters_
;
820 for (const scoped_refptr
<TraceMessageFilter
>& tmf
: trace_message_filters_
)
821 tmf
->SendProcessMemoryDumpRequest(args
);
824 bool TracingControllerImpl::IsCoordinatorProcess() const {
828 void TracingControllerImpl::OnProcessMemoryDumpResponse(
829 TraceMessageFilter
* trace_message_filter
,
832 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
833 BrowserThread::PostTask(
834 BrowserThread::UI
, FROM_HERE
,
835 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse
,
836 base::Unretained(this),
837 make_scoped_refptr(trace_message_filter
), dump_guid
,
842 TraceMessageFilterSet::iterator it
=
843 pending_memory_dump_filters_
.find(trace_message_filter
);
845 if (pending_memory_dump_guid_
!= dump_guid
||
846 it
== pending_memory_dump_filters_
.end()) {
847 DLOG(WARNING
) << "Received unexpected memory dump response: " << dump_guid
;
851 DCHECK_GT(pending_memory_dump_ack_count_
, 0);
852 --pending_memory_dump_ack_count_
;
853 pending_memory_dump_filters_
.erase(it
);
855 ++failed_memory_dump_count_
;
856 DLOG(WARNING
) << "Global memory dump failed because of NACK from child "
857 << trace_message_filter
->peer_pid();
859 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
862 void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64 dump_guid
,
864 DCHECK_GT(pending_memory_dump_ack_count_
, 0);
865 --pending_memory_dump_ack_count_
;
867 ++failed_memory_dump_count_
;
868 DLOG(WARNING
) << "Global memory dump aborted on the current process";
870 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
873 void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
874 if (pending_memory_dump_ack_count_
> 0)
877 DCHECK_NE(0u, pending_memory_dump_guid_
);
878 const bool global_success
= failed_memory_dump_count_
== 0;
879 if (!pending_memory_dump_callback_
.is_null()) {
880 pending_memory_dump_callback_
.Run(pending_memory_dump_guid_
,
882 pending_memory_dump_callback_
.Reset();
884 pending_memory_dump_guid_
= 0;
887 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring
) {
888 if (is_monitoring_
== is_monitoring
)
891 is_monitoring_
= is_monitoring
;
892 #if !defined(OS_ANDROID)
893 for (std::set
<TracingUI
*>::iterator it
= tracing_uis_
.begin();
894 it
!= tracing_uis_
.end(); it
++) {
895 (*it
)->OnMonitoringStateChanged(is_monitoring
);
900 } // namespace content