Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / tracing / tracing_controller_impl.cc
blobca480c70638cf829cc292c7cb2a683d7bc5474cb
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/debug/trace_event.h"
8 #include "base/file_util.h"
9 #include "base/json/string_escape.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "content/browser/tracing/trace_message_filter.h"
12 #include "content/browser/tracing/tracing_ui.h"
13 #include "content/common/child_process_messages.h"
14 #include "content/public/browser/browser_message_filter.h"
15 #include "content/public/common/content_switches.h"
17 #if defined(OS_CHROMEOS)
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "chromeos/dbus/debug_daemon_client.h"
20 #endif
22 #if defined(OS_WIN)
23 #include "content/browser/tracing/etw_system_event_consumer_win.h"
24 #endif
26 using base::debug::TraceLog;
27 using base::debug::TraceOptions;
28 using base::debug::CategoryFilter;
30 namespace content {
32 namespace {
34 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
35 LAZY_INSTANCE_INITIALIZER;
37 } // namespace
39 TracingController* TracingController::GetInstance() {
40 return TracingControllerImpl::GetInstance();
43 class TracingControllerImpl::ResultFile {
44 public:
45 explicit ResultFile(const base::FilePath& path);
46 void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) {
47 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
48 base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
49 base::Unretained(this), events_str_ptr));
51 void Close(const base::Closure& callback) {
52 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
53 base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
54 base::Unretained(this), callback));
56 void WriteSystemTrace(
57 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
58 BrowserThread::PostTask(
59 BrowserThread::FILE,
60 FROM_HERE,
61 base::Bind(&TracingControllerImpl::ResultFile::WriteSystemTraceTask,
62 base::Unretained(this), events_str_ptr));
65 const base::FilePath& path() const { return path_; }
67 private:
68 void OpenTask();
69 void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr);
70 void WriteSystemTraceTask(
71 const scoped_refptr<base::RefCountedString>& events_str_ptr);
72 void CloseTask(const base::Closure& callback);
74 FILE* file_;
75 base::FilePath path_;
76 bool has_at_least_one_result_;
77 scoped_refptr<base::RefCountedString> system_trace_;
79 DISALLOW_COPY_AND_ASSIGN(ResultFile);
82 TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path)
83 : file_(NULL),
84 path_(path),
85 has_at_least_one_result_(false) {
86 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
87 base::Bind(&TracingControllerImpl::ResultFile::OpenTask,
88 base::Unretained(this)));
91 void TracingControllerImpl::ResultFile::OpenTask() {
92 if (path_.empty())
93 base::CreateTemporaryFile(&path_);
94 file_ = base::OpenFile(path_, "w");
95 if (!file_) {
96 LOG(ERROR) << "Failed to open " << path_.value();
97 return;
99 const char* preamble = "{\"traceEvents\": [";
100 size_t written = fwrite(preamble, strlen(preamble), 1, file_);
101 DCHECK(written == 1);
104 void TracingControllerImpl::ResultFile::WriteTask(
105 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
106 if (!file_ || !events_str_ptr->data().size())
107 return;
109 // If there is already a result in the file, then put a comma
110 // before the next batch of results.
111 if (has_at_least_one_result_) {
112 size_t written = fwrite(",", 1, 1, file_);
113 DCHECK(written == 1);
115 has_at_least_one_result_ = true;
116 size_t written = fwrite(events_str_ptr->data().c_str(),
117 events_str_ptr->data().size(), 1,
118 file_);
119 DCHECK(written == 1);
122 void TracingControllerImpl::ResultFile::WriteSystemTraceTask(
123 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
124 system_trace_ = events_str_ptr;
127 void TracingControllerImpl::ResultFile::CloseTask(
128 const base::Closure& callback) {
129 if (!file_)
130 return;
132 const char* trailevents = "]";
133 size_t written = fwrite(trailevents, strlen(trailevents), 1, file_);
134 DCHECK(written == 1);
136 if (system_trace_.get()) {
137 #if defined(OS_WIN)
138 // The Windows kernel events are kept into a JSon format stored as string
139 // and must not be escaped.
140 std::string json_string = system_trace_->data();
141 #else
142 std::string json_string = base::GetQuotedJSONString(system_trace_->data());
143 #endif
145 const char* systemTraceHead = ",\n\"systemTraceEvents\": ";
146 written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_);
147 DCHECK(written == 1);
149 written = fwrite(json_string.data(), json_string.size(), 1, file_);
150 DCHECK(written == 1);
152 system_trace_ = NULL;
155 const char* trailout = "}";
156 written = fwrite(trailout, strlen(trailout), 1, file_);
157 DCHECK(written == 1);
158 base::CloseFile(file_);
159 file_ = NULL;
161 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
165 TracingControllerImpl::TracingControllerImpl() :
166 pending_disable_recording_ack_count_(0),
167 pending_capture_monitoring_snapshot_ack_count_(0),
168 pending_trace_buffer_percent_full_ack_count_(0),
169 maximum_trace_buffer_percent_full_(0),
170 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
171 // is specified in command line.
172 #if defined(OS_CHROMEOS) || defined(OS_WIN)
173 is_system_tracing_(false),
174 #endif
175 is_recording_(TraceLog::GetInstance()->IsEnabled()),
176 is_monitoring_(false) {
179 TracingControllerImpl::~TracingControllerImpl() {
180 // This is a Leaky instance.
181 NOTREACHED();
184 TracingControllerImpl* TracingControllerImpl::GetInstance() {
185 return g_controller.Pointer();
188 bool TracingControllerImpl::GetCategories(
189 const GetCategoriesDoneCallback& callback) {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192 // Known categories come back from child processes with the EndTracingAck
193 // message. So to get known categories, just begin and end tracing immediately
194 // afterwards. This will ping all the child processes for categories.
195 pending_get_categories_done_callback_ = callback;
196 if (!EnableRecording(
197 CategoryFilter("*"), TraceOptions(), EnableRecordingDoneCallback())) {
198 pending_get_categories_done_callback_.Reset();
199 return false;
202 bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback());
203 DCHECK(ok);
204 return true;
207 void TracingControllerImpl::SetEnabledOnFileThread(
208 const CategoryFilter& category_filter,
209 int mode,
210 const TraceOptions& trace_options,
211 const base::Closure& callback) {
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
214 TraceLog::GetInstance()->SetEnabled(
215 category_filter, static_cast<TraceLog::Mode>(mode), trace_options);
216 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
219 void TracingControllerImpl::SetDisabledOnFileThread(
220 const base::Closure& callback) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
223 TraceLog::GetInstance()->SetDisabled();
224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
227 bool TracingControllerImpl::EnableRecording(
228 const CategoryFilter& category_filter,
229 const TraceOptions& trace_options,
230 const EnableRecordingDoneCallback& callback) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
233 if (!can_enable_recording())
234 return false;
235 is_recording_ = true;
237 #if defined(OS_ANDROID)
238 if (pending_get_categories_done_callback_.is_null())
239 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
240 #endif
242 trace_options_ = trace_options;
244 if (trace_options.enable_systrace) {
245 #if defined(OS_CHROMEOS)
246 DCHECK(!is_system_tracing_);
247 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
248 StartSystemTracing();
249 is_system_tracing_ = true;
250 #elif defined(OS_WIN)
251 DCHECK(!is_system_tracing_);
252 is_system_tracing_ =
253 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
254 #endif
258 base::Closure on_enable_recording_done_callback =
259 base::Bind(&TracingControllerImpl::OnEnableRecordingDone,
260 base::Unretained(this),
261 category_filter, trace_options, callback);
262 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
263 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
264 base::Unretained(this),
265 category_filter,
266 base::debug::TraceLog::RECORDING_MODE,
267 trace_options,
268 on_enable_recording_done_callback));
269 return true;
272 void TracingControllerImpl::OnEnableRecordingDone(
273 const CategoryFilter& category_filter,
274 const TraceOptions& trace_options,
275 const EnableRecordingDoneCallback& callback) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
278 // Notify all child processes.
279 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
280 it != trace_message_filters_.end(); ++it) {
281 it->get()->SendBeginTracing(category_filter, trace_options);
284 if (!callback.is_null())
285 callback.Run();
288 bool TracingControllerImpl::DisableRecording(
289 const base::FilePath& result_file_path,
290 const TracingFileResultCallback& callback) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
293 if (!can_disable_recording())
294 return false;
296 trace_options_ = TraceOptions();
297 // Disable local trace early to avoid traces during end-tracing process from
298 // interfering with the process.
299 base::Closure on_disable_recording_done_callback =
300 base::Bind(&TracingControllerImpl::OnDisableRecordingDone,
301 base::Unretained(this),
302 result_file_path, callback);
303 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
304 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
305 base::Unretained(this),
306 on_disable_recording_done_callback));
307 return true;
310 void TracingControllerImpl::OnDisableRecordingDone(
311 const base::FilePath& result_file_path,
312 const TracingFileResultCallback& callback) {
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
315 pending_disable_recording_done_callback_ = callback;
317 #if defined(OS_ANDROID)
318 if (pending_get_categories_done_callback_.is_null())
319 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
320 #endif
322 if (!callback.is_null() || !result_file_path.empty())
323 result_file_.reset(new ResultFile(result_file_path));
325 // Count myself (local trace) in pending_disable_recording_ack_count_,
326 // acked below.
327 pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
328 pending_disable_recording_filters_ = trace_message_filters_;
330 #if defined(OS_CHROMEOS) || defined(OS_WIN)
331 if (is_system_tracing_) {
332 // Disable system tracing.
333 is_system_tracing_ = false;
334 ++pending_disable_recording_ack_count_;
336 #if defined(OS_CHROMEOS)
337 scoped_refptr<base::TaskRunner> task_runner =
338 BrowserThread::GetBlockingPool();
339 chromeos::DBusThreadManager::Get()
340 ->GetDebugDaemonClient()
341 ->RequestStopSystemTracing(
342 task_runner,
343 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
344 base::Unretained(this)));
345 #elif defined(OS_WIN)
346 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
347 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
348 base::Unretained(this)));
349 #endif
351 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
353 // Handle special case of zero child processes by immediately flushing the
354 // trace log. Once the flush has completed the caller will be notified that
355 // tracing has ended.
356 if (pending_disable_recording_ack_count_ == 1) {
357 // Flush asynchronously now, because we don't have any children to wait for.
358 TraceLog::GetInstance()->Flush(
359 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
360 base::Unretained(this)));
363 // Notify all child processes.
364 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
365 it != trace_message_filters_.end(); ++it) {
366 it->get()->SendEndTracing();
370 bool TracingControllerImpl::EnableMonitoring(
371 const CategoryFilter& category_filter,
372 const TraceOptions& trace_options,
373 const EnableMonitoringDoneCallback& callback) {
374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
376 if (!can_enable_monitoring())
377 return false;
378 OnMonitoringStateChanged(true);
380 #if defined(OS_ANDROID)
381 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
382 #endif
384 trace_options_ = trace_options;
386 base::Closure on_enable_monitoring_done_callback =
387 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
388 base::Unretained(this),
389 category_filter, trace_options, callback);
390 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
391 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
392 base::Unretained(this),
393 category_filter,
394 base::debug::TraceLog::MONITORING_MODE,
395 trace_options,
396 on_enable_monitoring_done_callback));
397 return true;
400 void TracingControllerImpl::OnEnableMonitoringDone(
401 const CategoryFilter& category_filter,
402 const TraceOptions& trace_options,
403 const EnableMonitoringDoneCallback& callback) {
404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
406 // Notify all child processes.
407 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
408 it != trace_message_filters_.end(); ++it) {
409 it->get()->SendEnableMonitoring(category_filter, trace_options);
412 if (!callback.is_null())
413 callback.Run();
416 bool TracingControllerImpl::DisableMonitoring(
417 const DisableMonitoringDoneCallback& callback) {
418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
420 if (!can_disable_monitoring())
421 return false;
423 trace_options_ = TraceOptions();
424 base::Closure on_disable_monitoring_done_callback =
425 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
426 base::Unretained(this), callback);
427 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
428 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
429 base::Unretained(this),
430 on_disable_monitoring_done_callback));
431 return true;
434 void TracingControllerImpl::OnDisableMonitoringDone(
435 const DisableMonitoringDoneCallback& callback) {
436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
438 OnMonitoringStateChanged(false);
440 // Notify all child processes.
441 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
442 it != trace_message_filters_.end(); ++it) {
443 it->get()->SendDisableMonitoring();
446 if (!callback.is_null())
447 callback.Run();
450 void TracingControllerImpl::GetMonitoringStatus(
451 bool* out_enabled,
452 CategoryFilter* out_category_filter,
453 TraceOptions* out_trace_options) {
454 *out_enabled = is_monitoring_;
455 *out_category_filter = TraceLog::GetInstance()->GetCurrentCategoryFilter();
456 *out_trace_options = trace_options_;
459 bool TracingControllerImpl::CaptureMonitoringSnapshot(
460 const base::FilePath& result_file_path,
461 const TracingFileResultCallback& callback) {
462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
464 if (!can_disable_monitoring())
465 return false;
467 if (callback.is_null() && result_file_path.empty())
468 return false;
470 pending_capture_monitoring_snapshot_done_callback_ = callback;
471 monitoring_snapshot_file_.reset(new ResultFile(result_file_path));
473 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
474 // acked below.
475 pending_capture_monitoring_snapshot_ack_count_ =
476 trace_message_filters_.size() + 1;
477 pending_capture_monitoring_filters_ = trace_message_filters_;
479 // Handle special case of zero child processes by immediately flushing the
480 // trace log. Once the flush has completed the caller will be notified that
481 // the capture snapshot has ended.
482 if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
483 // Flush asynchronously now, because we don't have any children to wait for.
484 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
485 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
486 base::Unretained(this)));
489 // Notify all child processes.
490 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
491 it != trace_message_filters_.end(); ++it) {
492 it->get()->SendCaptureMonitoringSnapshot();
495 #if defined(OS_ANDROID)
496 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
497 #endif
499 return true;
502 bool TracingControllerImpl::GetTraceBufferPercentFull(
503 const GetTraceBufferPercentFullCallback& callback) {
504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
506 if (!can_get_trace_buffer_percent_full() || callback.is_null())
507 return false;
509 pending_trace_buffer_percent_full_callback_ = callback;
511 // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below.
512 pending_trace_buffer_percent_full_ack_count_ =
513 trace_message_filters_.size() + 1;
514 pending_trace_buffer_percent_full_filters_ = trace_message_filters_;
515 maximum_trace_buffer_percent_full_ = 0;
517 // Call OnTraceBufferPercentFullReply unconditionally for the browser process.
518 // This will result in immediate execution of the callback if there are no
519 // child processes.
520 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
521 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
522 base::Unretained(this),
523 scoped_refptr<TraceMessageFilter>(),
524 TraceLog::GetInstance()->GetBufferPercentFull()));
526 // Notify all child processes.
527 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
528 it != trace_message_filters_.end(); ++it) {
529 it->get()->SendGetTraceBufferPercentFull();
531 return true;
534 bool TracingControllerImpl::SetWatchEvent(
535 const std::string& category_name,
536 const std::string& event_name,
537 const WatchEventCallback& callback) {
538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
540 if (callback.is_null())
541 return false;
543 watch_category_name_ = category_name;
544 watch_event_name_ = event_name;
545 watch_event_callback_ = callback;
547 TraceLog::GetInstance()->SetWatchEvent(
548 category_name, event_name,
549 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
550 base::Unretained(this)));
552 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
553 it != trace_message_filters_.end(); ++it) {
554 it->get()->SendSetWatchEvent(category_name, event_name);
556 return true;
559 bool TracingControllerImpl::CancelWatchEvent() {
560 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562 if (!can_cancel_watch_event())
563 return false;
565 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
566 it != trace_message_filters_.end(); ++it) {
567 it->get()->SendCancelWatchEvent();
570 watch_event_callback_.Reset();
571 return true;
574 void TracingControllerImpl::AddTraceMessageFilter(
575 TraceMessageFilter* trace_message_filter) {
576 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
577 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
578 base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
579 base::Unretained(this),
580 make_scoped_refptr(trace_message_filter)));
581 return;
584 trace_message_filters_.insert(trace_message_filter);
585 if (can_cancel_watch_event()) {
586 trace_message_filter->SendSetWatchEvent(watch_category_name_,
587 watch_event_name_);
589 if (can_disable_recording()) {
590 trace_message_filter->SendBeginTracing(
591 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
592 TraceLog::GetInstance()->GetCurrentTraceOptions());
594 if (can_disable_monitoring()) {
595 trace_message_filter->SendEnableMonitoring(
596 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
597 TraceLog::GetInstance()->GetCurrentTraceOptions());
601 void TracingControllerImpl::RemoveTraceMessageFilter(
602 TraceMessageFilter* trace_message_filter) {
603 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
604 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
605 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
606 base::Unretained(this),
607 make_scoped_refptr(trace_message_filter)));
608 return;
611 // If a filter is removed while a response from that filter is pending then
612 // simulate the response. Otherwise the response count will be wrong and the
613 // completion callback will never be executed.
614 if (pending_disable_recording_ack_count_ > 0) {
615 TraceMessageFilterSet::const_iterator it =
616 pending_disable_recording_filters_.find(trace_message_filter);
617 if (it != pending_disable_recording_filters_.end()) {
618 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
619 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
620 base::Unretained(this),
621 make_scoped_refptr(trace_message_filter),
622 std::vector<std::string>()));
625 if (pending_capture_monitoring_snapshot_ack_count_ > 0) {
626 TraceMessageFilterSet::const_iterator it =
627 pending_capture_monitoring_filters_.find(trace_message_filter);
628 if (it != pending_capture_monitoring_filters_.end()) {
629 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
630 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
631 base::Unretained(this),
632 make_scoped_refptr(trace_message_filter)));
635 if (pending_trace_buffer_percent_full_ack_count_ > 0) {
636 TraceMessageFilterSet::const_iterator it =
637 pending_trace_buffer_percent_full_filters_.find(trace_message_filter);
638 if (it != pending_trace_buffer_percent_full_filters_.end()) {
639 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
640 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
641 base::Unretained(this),
642 make_scoped_refptr(trace_message_filter),
643 0));
647 trace_message_filters_.erase(trace_message_filter);
650 void TracingControllerImpl::OnDisableRecordingAcked(
651 TraceMessageFilter* trace_message_filter,
652 const std::vector<std::string>& known_category_groups) {
653 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
654 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
655 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
656 base::Unretained(this),
657 make_scoped_refptr(trace_message_filter),
658 known_category_groups));
659 return;
662 // Merge known_category_groups with known_category_groups_
663 known_category_groups_.insert(known_category_groups.begin(),
664 known_category_groups.end());
666 if (pending_disable_recording_ack_count_ == 0)
667 return;
669 if (trace_message_filter &&
670 !pending_disable_recording_filters_.erase(trace_message_filter)) {
671 // The response from the specified message filter has already been received.
672 return;
675 if (--pending_disable_recording_ack_count_ == 1) {
676 // All acks from subprocesses have been received. Now flush the local trace.
677 // During or after this call, our OnLocalTraceDataCollected will be
678 // called with the last of the local trace data.
679 TraceLog::GetInstance()->Flush(
680 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
681 base::Unretained(this)));
682 return;
685 if (pending_disable_recording_ack_count_ != 0)
686 return;
688 OnDisableRecordingComplete();
691 void TracingControllerImpl::OnDisableRecordingComplete() {
692 // All acks (including from the subprocesses and the local trace) have been
693 // received.
694 is_recording_ = false;
696 // Trigger callback if one is set.
697 if (!pending_get_categories_done_callback_.is_null()) {
698 pending_get_categories_done_callback_.Run(known_category_groups_);
699 pending_get_categories_done_callback_.Reset();
700 } else if (result_file_) {
701 result_file_->Close(
702 base::Bind(&TracingControllerImpl::OnResultFileClosed,
703 base::Unretained(this)));
707 void TracingControllerImpl::OnResultFileClosed() {
708 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
710 if (!result_file_)
711 return;
713 if (!pending_disable_recording_done_callback_.is_null()) {
714 pending_disable_recording_done_callback_.Run(result_file_->path());
715 pending_disable_recording_done_callback_.Reset();
717 result_file_.reset();
720 #if defined(OS_CHROMEOS) || defined(OS_WIN)
721 void TracingControllerImpl::OnEndSystemTracingAcked(
722 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
725 if (result_file_)
726 result_file_->WriteSystemTrace(events_str_ptr);
728 DCHECK(!is_system_tracing_);
729 std::vector<std::string> category_groups;
730 OnDisableRecordingAcked(NULL, category_groups);
732 #endif
734 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
735 TraceMessageFilter* trace_message_filter) {
736 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
737 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
738 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
739 base::Unretained(this),
740 make_scoped_refptr(trace_message_filter)));
741 return;
744 if (pending_capture_monitoring_snapshot_ack_count_ == 0)
745 return;
747 if (trace_message_filter &&
748 !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
749 // The response from the specified message filter has already been received.
750 return;
753 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
754 // All acks from subprocesses have been received. Now flush the local trace.
755 // During or after this call, our OnLocalMonitoringTraceDataCollected
756 // will be called with the last of the local trace data.
757 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
758 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
759 base::Unretained(this)));
760 return;
763 if (pending_capture_monitoring_snapshot_ack_count_ != 0)
764 return;
766 if (monitoring_snapshot_file_) {
767 monitoring_snapshot_file_->Close(
768 base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed,
769 base::Unretained(this)));
773 void TracingControllerImpl::OnMonitoringSnapshotFileClosed() {
774 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
776 if (!monitoring_snapshot_file_)
777 return;
779 if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
780 pending_capture_monitoring_snapshot_done_callback_.Run(
781 monitoring_snapshot_file_->path());
782 pending_capture_monitoring_snapshot_done_callback_.Reset();
784 monitoring_snapshot_file_.reset();
787 void TracingControllerImpl::OnTraceDataCollected(
788 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
789 // OnTraceDataCollected may be called from any browser thread, either by the
790 // local event trace system or from child processes via TraceMessageFilter.
791 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
792 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
793 base::Bind(&TracingControllerImpl::OnTraceDataCollected,
794 base::Unretained(this), events_str_ptr));
795 return;
798 if (result_file_)
799 result_file_->Write(events_str_ptr);
802 void TracingControllerImpl::OnMonitoringTraceDataCollected(
803 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
804 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
805 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
806 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
807 base::Unretained(this), events_str_ptr));
808 return;
811 if (monitoring_snapshot_file_)
812 monitoring_snapshot_file_->Write(events_str_ptr);
815 void TracingControllerImpl::OnLocalTraceDataCollected(
816 const scoped_refptr<base::RefCountedString>& events_str_ptr,
817 bool has_more_events) {
818 if (events_str_ptr->data().size())
819 OnTraceDataCollected(events_str_ptr);
821 if (has_more_events)
822 return;
824 // Simulate an DisableRecordingAcked for the local trace.
825 std::vector<std::string> category_groups;
826 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
827 OnDisableRecordingAcked(NULL, category_groups);
830 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
831 const scoped_refptr<base::RefCountedString>& events_str_ptr,
832 bool has_more_events) {
833 if (events_str_ptr->data().size())
834 OnMonitoringTraceDataCollected(events_str_ptr);
836 if (has_more_events)
837 return;
839 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
840 OnCaptureMonitoringSnapshotAcked(NULL);
843 void TracingControllerImpl::OnTraceBufferPercentFullReply(
844 TraceMessageFilter* trace_message_filter,
845 float percent_full) {
846 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
847 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
848 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
849 base::Unretained(this),
850 make_scoped_refptr(trace_message_filter),
851 percent_full));
852 return;
855 if (pending_trace_buffer_percent_full_ack_count_ == 0)
856 return;
858 if (trace_message_filter &&
859 !pending_trace_buffer_percent_full_filters_.erase(trace_message_filter)) {
860 // The response from the specified message filter has already been received.
861 return;
864 maximum_trace_buffer_percent_full_ =
865 std::max(maximum_trace_buffer_percent_full_, percent_full);
867 if (--pending_trace_buffer_percent_full_ack_count_ == 0) {
868 // Trigger callback if one is set.
869 pending_trace_buffer_percent_full_callback_.Run(
870 maximum_trace_buffer_percent_full_);
871 pending_trace_buffer_percent_full_callback_.Reset();
875 void TracingControllerImpl::OnWatchEventMatched() {
876 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
877 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
878 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
879 base::Unretained(this)));
880 return;
883 if (!watch_event_callback_.is_null())
884 watch_event_callback_.Run();
887 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
888 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
889 tracing_uis_.insert(tracing_ui);
892 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
893 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui);
894 DCHECK(it != tracing_uis_.end());
895 tracing_uis_.erase(it);
898 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
899 if (is_monitoring_ == is_monitoring)
900 return;
902 is_monitoring_ = is_monitoring;
903 #if !defined(OS_ANDROID)
904 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
905 it != tracing_uis_.end(); it++) {
906 (*it)->OnMonitoringStateChanged(is_monitoring);
908 #endif
911 } // namespace content