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"
5
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"
16
17 #if defined(OS_CHROMEOS)
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "chromeos/dbus/debug_daemon_client.h"
20 #endif
21
22 #if defined(OS_WIN)
23 #include "content/browser/tracing/etw_system_event_consumer_win.h"
24 #endif
25
26 using base::debug::TraceLog;
27
28 namespace content {
29
30 namespace {
31
32 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
33 LAZY_INSTANCE_INITIALIZER;
34
35 } // namespace
36
GetInstance()37 TracingController* TracingController::GetInstance() {
38 return TracingControllerImpl::GetInstance();
39 }
40
41 class TracingControllerImpl::ResultFile {
42 public:
43 explicit ResultFile(const base::FilePath& path);
Write(const scoped_refptr<base::RefCountedString> & events_str_ptr)44 void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) {
45 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
46 base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
47 base::Unretained(this), events_str_ptr));
48 }
Close(const base::Closure & callback)49 void Close(const base::Closure& callback) {
50 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
51 base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
52 base::Unretained(this), callback));
53 }
WriteSystemTrace(const scoped_refptr<base::RefCountedString> & events_str_ptr)54 void WriteSystemTrace(
55 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
56 BrowserThread::PostTask(
57 BrowserThread::FILE,
58 FROM_HERE,
59 base::Bind(&TracingControllerImpl::ResultFile::WriteSystemTraceTask,
60 base::Unretained(this), events_str_ptr));
61 }
62
path() const63 const base::FilePath& path() const { return path_; }
64
65 private:
66 void OpenTask();
67 void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr);
68 void WriteSystemTraceTask(
69 const scoped_refptr<base::RefCountedString>& events_str_ptr);
70 void CloseTask(const base::Closure& callback);
71
72 FILE* file_;
73 base::FilePath path_;
74 bool has_at_least_one_result_;
75 scoped_refptr<base::RefCountedString> system_trace_;
76
77 DISALLOW_COPY_AND_ASSIGN(ResultFile);
78 };
79
ResultFile(const base::FilePath & path)80 TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path)
81 : file_(NULL),
82 path_(path),
83 has_at_least_one_result_(false) {
84 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
85 base::Bind(&TracingControllerImpl::ResultFile::OpenTask,
86 base::Unretained(this)));
87 }
88
OpenTask()89 void TracingControllerImpl::ResultFile::OpenTask() {
90 if (path_.empty())
91 base::CreateTemporaryFile(&path_);
92 file_ = base::OpenFile(path_, "w");
93 if (!file_) {
94 LOG(ERROR) << "Failed to open " << path_.value();
95 return;
96 }
97 const char* preamble = "{\"traceEvents\": [";
98 size_t written = fwrite(preamble, strlen(preamble), 1, file_);
99 DCHECK(written == 1);
100 }
101
WriteTask(const scoped_refptr<base::RefCountedString> & events_str_ptr)102 void TracingControllerImpl::ResultFile::WriteTask(
103 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
104 if (!file_ || !events_str_ptr->data().size())
105 return;
106
107 // If there is already a result in the file, then put a comma
108 // before the next batch of results.
109 if (has_at_least_one_result_) {
110 size_t written = fwrite(",", 1, 1, file_);
111 DCHECK(written == 1);
112 }
113 has_at_least_one_result_ = true;
114 size_t written = fwrite(events_str_ptr->data().c_str(),
115 events_str_ptr->data().size(), 1,
116 file_);
117 DCHECK(written == 1);
118 }
119
WriteSystemTraceTask(const scoped_refptr<base::RefCountedString> & events_str_ptr)120 void TracingControllerImpl::ResultFile::WriteSystemTraceTask(
121 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
122 system_trace_ = events_str_ptr;
123 }
124
CloseTask(const base::Closure & callback)125 void TracingControllerImpl::ResultFile::CloseTask(
126 const base::Closure& callback) {
127 if (!file_)
128 return;
129
130 const char* trailevents = "]";
131 size_t written = fwrite(trailevents, strlen(trailevents), 1, file_);
132 DCHECK(written == 1);
133
134 if (system_trace_) {
135 #if defined(OS_WIN)
136 // The Windows kernel events are kept into a JSon format stored as string
137 // and must not be escaped.
138 std::string json_string = system_trace_->data();
139 #else
140 std::string json_string = base::GetQuotedJSONString(system_trace_->data());
141 #endif
142
143 const char* systemTraceHead = ",\n\"systemTraceEvents\": ";
144 written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_);
145 DCHECK(written == 1);
146
147 written = fwrite(json_string.data(), json_string.size(), 1, file_);
148 DCHECK(written == 1);
149
150 system_trace_ = NULL;
151 }
152
153 const char* trailout = "}";
154 written = fwrite(trailout, strlen(trailout), 1, file_);
155 DCHECK(written == 1);
156 base::CloseFile(file_);
157 file_ = NULL;
158
159 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
160 }
161
162
TracingControllerImpl()163 TracingControllerImpl::TracingControllerImpl() :
164 pending_disable_recording_ack_count_(0),
165 pending_capture_monitoring_snapshot_ack_count_(0),
166 pending_trace_buffer_percent_full_ack_count_(0),
167 maximum_trace_buffer_percent_full_(0),
168 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
169 // is specified in command line.
170 #if defined(OS_CHROMEOS) || defined(OS_WIN)
171 is_system_tracing_(false),
172 #endif
173 is_recording_(TraceLog::GetInstance()->IsEnabled()),
174 is_monitoring_(false) {
175 }
176
~TracingControllerImpl()177 TracingControllerImpl::~TracingControllerImpl() {
178 // This is a Leaky instance.
179 NOTREACHED();
180 }
181
GetInstance()182 TracingControllerImpl* TracingControllerImpl::GetInstance() {
183 return g_controller.Pointer();
184 }
185
GetCategories(const GetCategoriesDoneCallback & callback)186 bool TracingControllerImpl::GetCategories(
187 const GetCategoriesDoneCallback& callback) {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189
190 // Known categories come back from child processes with the EndTracingAck
191 // message. So to get known categories, just begin and end tracing immediately
192 // afterwards. This will ping all the child processes for categories.
193 pending_get_categories_done_callback_ = callback;
194 if (!EnableRecording("*", TracingController::Options(),
195 EnableRecordingDoneCallback())) {
196 pending_get_categories_done_callback_.Reset();
197 return false;
198 }
199
200 bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback());
201 DCHECK(ok);
202 return true;
203 }
204
SetEnabledOnFileThread(const std::string & category_filter,int mode,int trace_options,const base::Closure & callback)205 void TracingControllerImpl::SetEnabledOnFileThread(
206 const std::string& category_filter,
207 int mode,
208 int trace_options,
209 const base::Closure& callback) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
211
212 TraceLog::GetInstance()->SetEnabled(
213 base::debug::CategoryFilter(category_filter),
214 static_cast<TraceLog::Mode>(mode),
215 static_cast<TraceLog::Options>(trace_options));
216 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
217 }
218
SetDisabledOnFileThread(const base::Closure & callback)219 void TracingControllerImpl::SetDisabledOnFileThread(
220 const base::Closure& callback) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
222
223 TraceLog::GetInstance()->SetDisabled();
224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
225 }
226
EnableRecording(const std::string & category_filter,TracingController::Options options,const EnableRecordingDoneCallback & callback)227 bool TracingControllerImpl::EnableRecording(
228 const std::string& category_filter,
229 TracingController::Options options,
230 const EnableRecordingDoneCallback& callback) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232
233 if (!can_enable_recording())
234 return false;
235 is_recording_ = true;
236
237 #if defined(OS_ANDROID)
238 if (pending_get_categories_done_callback_.is_null())
239 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
240 #endif
241
242 options_ = options;
243 int trace_options = (options & RECORD_CONTINUOUSLY) ?
244 TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL;
245 if (options & ENABLE_SAMPLING) {
246 trace_options |= TraceLog::ENABLE_SAMPLING;
247 }
248
249 if (options & ENABLE_SYSTRACE) {
250 #if defined(OS_CHROMEOS)
251 DCHECK(!is_system_tracing_);
252 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
253 StartSystemTracing();
254 is_system_tracing_ = true;
255 #elif defined(OS_WIN)
256 DCHECK(!is_system_tracing_);
257 is_system_tracing_ =
258 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
259 #endif
260 }
261
262
263 base::Closure on_enable_recording_done_callback =
264 base::Bind(&TracingControllerImpl::OnEnableRecordingDone,
265 base::Unretained(this),
266 category_filter, trace_options, callback);
267 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
268 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
269 base::Unretained(this),
270 category_filter,
271 base::debug::TraceLog::RECORDING_MODE,
272 trace_options,
273 on_enable_recording_done_callback));
274 return true;
275 }
276
OnEnableRecordingDone(const std::string & category_filter,int trace_options,const EnableRecordingDoneCallback & callback)277 void TracingControllerImpl::OnEnableRecordingDone(
278 const std::string& category_filter,
279 int trace_options,
280 const EnableRecordingDoneCallback& callback) {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
282
283 // Notify all child processes.
284 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
285 it != trace_message_filters_.end(); ++it) {
286 it->get()->SendBeginTracing(category_filter,
287 static_cast<TraceLog::Options>(trace_options));
288 }
289
290 if (!callback.is_null())
291 callback.Run();
292 }
293
DisableRecording(const base::FilePath & result_file_path,const TracingFileResultCallback & callback)294 bool TracingControllerImpl::DisableRecording(
295 const base::FilePath& result_file_path,
296 const TracingFileResultCallback& callback) {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
298
299 if (!can_disable_recording())
300 return false;
301
302 options_ = TracingController::Options();
303 // Disable local trace early to avoid traces during end-tracing process from
304 // interfering with the process.
305 base::Closure on_disable_recording_done_callback =
306 base::Bind(&TracingControllerImpl::OnDisableRecordingDone,
307 base::Unretained(this),
308 result_file_path, callback);
309 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
310 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
311 base::Unretained(this),
312 on_disable_recording_done_callback));
313 return true;
314 }
315
OnDisableRecordingDone(const base::FilePath & result_file_path,const TracingFileResultCallback & callback)316 void TracingControllerImpl::OnDisableRecordingDone(
317 const base::FilePath& result_file_path,
318 const TracingFileResultCallback& callback) {
319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
320
321 pending_disable_recording_done_callback_ = callback;
322
323 #if defined(OS_ANDROID)
324 if (pending_get_categories_done_callback_.is_null())
325 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
326 #endif
327
328 if (!callback.is_null() || !result_file_path.empty())
329 result_file_.reset(new ResultFile(result_file_path));
330
331 // Count myself (local trace) in pending_disable_recording_ack_count_,
332 // acked below.
333 pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
334 pending_disable_recording_filters_ = trace_message_filters_;
335
336 #if defined(OS_CHROMEOS) || defined(OS_WIN)
337 if (is_system_tracing_) {
338 // Disable system tracing.
339 is_system_tracing_ = false;
340 ++pending_disable_recording_ack_count_;
341
342 #if defined(OS_CHROMEOS)
343 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
344 RequestStopSystemTracing(
345 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
346 base::Unretained(this)));
347 #elif defined(OS_WIN)
348 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
349 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
350 base::Unretained(this)));
351 #endif
352 }
353 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
354
355 // Handle special case of zero child processes by immediately flushing the
356 // trace log. Once the flush has completed the caller will be notified that
357 // tracing has ended.
358 if (pending_disable_recording_ack_count_ == 1) {
359 // Flush asynchronously now, because we don't have any children to wait for.
360 TraceLog::GetInstance()->Flush(
361 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
362 base::Unretained(this)));
363 }
364
365 // Notify all child processes.
366 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
367 it != trace_message_filters_.end(); ++it) {
368 it->get()->SendEndTracing();
369 }
370 }
371
EnableMonitoring(const std::string & category_filter,TracingController::Options options,const EnableMonitoringDoneCallback & callback)372 bool TracingControllerImpl::EnableMonitoring(
373 const std::string& category_filter,
374 TracingController::Options options,
375 const EnableMonitoringDoneCallback& callback) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377
378 if (!can_enable_monitoring())
379 return false;
380 OnMonitoringStateChanged(true);
381
382 #if defined(OS_ANDROID)
383 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
384 #endif
385
386 options_ = options;
387 int trace_options = 0;
388 if (options & ENABLE_SAMPLING)
389 trace_options |= TraceLog::ENABLE_SAMPLING;
390
391 base::Closure on_enable_monitoring_done_callback =
392 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
393 base::Unretained(this),
394 category_filter, trace_options, callback);
395 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
396 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
397 base::Unretained(this),
398 category_filter,
399 base::debug::TraceLog::MONITORING_MODE,
400 trace_options,
401 on_enable_monitoring_done_callback));
402 return true;
403 }
404
OnEnableMonitoringDone(const std::string & category_filter,int trace_options,const EnableMonitoringDoneCallback & callback)405 void TracingControllerImpl::OnEnableMonitoringDone(
406 const std::string& category_filter,
407 int trace_options,
408 const EnableMonitoringDoneCallback& callback) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410
411 // Notify all child processes.
412 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
413 it != trace_message_filters_.end(); ++it) {
414 it->get()->SendEnableMonitoring(category_filter,
415 static_cast<TraceLog::Options>(trace_options));
416 }
417
418 if (!callback.is_null())
419 callback.Run();
420 }
421
DisableMonitoring(const DisableMonitoringDoneCallback & callback)422 bool TracingControllerImpl::DisableMonitoring(
423 const DisableMonitoringDoneCallback& callback) {
424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
425
426 if (!can_disable_monitoring())
427 return false;
428
429 options_ = TracingController::Options();
430 base::Closure on_disable_monitoring_done_callback =
431 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
432 base::Unretained(this), callback);
433 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
434 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
435 base::Unretained(this),
436 on_disable_monitoring_done_callback));
437 return true;
438 }
439
OnDisableMonitoringDone(const DisableMonitoringDoneCallback & callback)440 void TracingControllerImpl::OnDisableMonitoringDone(
441 const DisableMonitoringDoneCallback& callback) {
442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
443
444 OnMonitoringStateChanged(false);
445
446 // Notify all child processes.
447 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
448 it != trace_message_filters_.end(); ++it) {
449 it->get()->SendDisableMonitoring();
450 }
451
452 if (!callback.is_null())
453 callback.Run();
454 }
455
GetMonitoringStatus(bool * out_enabled,std::string * out_category_filter,TracingController::Options * out_options)456 void TracingControllerImpl::GetMonitoringStatus(
457 bool* out_enabled,
458 std::string* out_category_filter,
459 TracingController::Options* out_options) {
460 *out_enabled = is_monitoring_;
461 *out_category_filter =
462 TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString();
463 *out_options = options_;
464 }
465
CaptureMonitoringSnapshot(const base::FilePath & result_file_path,const TracingFileResultCallback & callback)466 bool TracingControllerImpl::CaptureMonitoringSnapshot(
467 const base::FilePath& result_file_path,
468 const TracingFileResultCallback& callback) {
469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
470
471 if (!can_disable_monitoring())
472 return false;
473
474 if (callback.is_null() && result_file_path.empty())
475 return false;
476
477 pending_capture_monitoring_snapshot_done_callback_ = callback;
478 monitoring_snapshot_file_.reset(new ResultFile(result_file_path));
479
480 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
481 // acked below.
482 pending_capture_monitoring_snapshot_ack_count_ =
483 trace_message_filters_.size() + 1;
484 pending_capture_monitoring_filters_ = trace_message_filters_;
485
486 // Handle special case of zero child processes by immediately flushing the
487 // trace log. Once the flush has completed the caller will be notified that
488 // the capture snapshot has ended.
489 if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
490 // Flush asynchronously now, because we don't have any children to wait for.
491 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
492 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
493 base::Unretained(this)));
494 }
495
496 // Notify all child processes.
497 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
498 it != trace_message_filters_.end(); ++it) {
499 it->get()->SendCaptureMonitoringSnapshot();
500 }
501
502 #if defined(OS_ANDROID)
503 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
504 #endif
505
506 return true;
507 }
508
GetTraceBufferPercentFull(const GetTraceBufferPercentFullCallback & callback)509 bool TracingControllerImpl::GetTraceBufferPercentFull(
510 const GetTraceBufferPercentFullCallback& callback) {
511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
512
513 if (!can_get_trace_buffer_percent_full() || callback.is_null())
514 return false;
515
516 pending_trace_buffer_percent_full_callback_ = callback;
517
518 // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below.
519 pending_trace_buffer_percent_full_ack_count_ =
520 trace_message_filters_.size() + 1;
521 pending_trace_buffer_percent_full_filters_ = trace_message_filters_;
522 maximum_trace_buffer_percent_full_ = 0;
523
524 // Call OnTraceBufferPercentFullReply unconditionally for the browser process.
525 // This will result in immediate execution of the callback if there are no
526 // child processes.
527 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
528 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
529 base::Unretained(this),
530 scoped_refptr<TraceMessageFilter>(),
531 TraceLog::GetInstance()->GetBufferPercentFull()));
532
533 // Notify all child processes.
534 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
535 it != trace_message_filters_.end(); ++it) {
536 it->get()->SendGetTraceBufferPercentFull();
537 }
538 return true;
539 }
540
SetWatchEvent(const std::string & category_name,const std::string & event_name,const WatchEventCallback & callback)541 bool TracingControllerImpl::SetWatchEvent(
542 const std::string& category_name,
543 const std::string& event_name,
544 const WatchEventCallback& callback) {
545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
546
547 if (callback.is_null())
548 return false;
549
550 watch_category_name_ = category_name;
551 watch_event_name_ = event_name;
552 watch_event_callback_ = callback;
553
554 TraceLog::GetInstance()->SetWatchEvent(
555 category_name, event_name,
556 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
557 base::Unretained(this)));
558
559 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
560 it != trace_message_filters_.end(); ++it) {
561 it->get()->SendSetWatchEvent(category_name, event_name);
562 }
563 return true;
564 }
565
CancelWatchEvent()566 bool TracingControllerImpl::CancelWatchEvent() {
567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
568
569 if (!can_cancel_watch_event())
570 return false;
571
572 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
573 it != trace_message_filters_.end(); ++it) {
574 it->get()->SendCancelWatchEvent();
575 }
576
577 watch_event_callback_.Reset();
578 return true;
579 }
580
AddTraceMessageFilter(TraceMessageFilter * trace_message_filter)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)));
588 return;
589 }
590
591 trace_message_filters_.insert(trace_message_filter);
592 if (can_cancel_watch_event()) {
593 trace_message_filter->SendSetWatchEvent(watch_category_name_,
594 watch_event_name_);
595 }
596 if (can_disable_recording()) {
597 trace_message_filter->SendBeginTracing(
598 TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(),
599 TraceLog::GetInstance()->trace_options());
600 }
601 if (can_disable_monitoring()) {
602 trace_message_filter->SendEnableMonitoring(
603 TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(),
604 TraceLog::GetInstance()->trace_options());
605 }
606 }
607
RemoveTraceMessageFilter(TraceMessageFilter * trace_message_filter)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)));
615 return;
616 }
617
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>()));
630 }
631 }
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)));
640 }
641 }
642 if (pending_trace_buffer_percent_full_ack_count_ > 0) {
643 TraceMessageFilterSet::const_iterator it =
644 pending_trace_buffer_percent_full_filters_.find(trace_message_filter);
645 if (it != pending_trace_buffer_percent_full_filters_.end()) {
646 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
647 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
648 base::Unretained(this),
649 make_scoped_refptr(trace_message_filter),
650 0));
651 }
652 }
653
654 trace_message_filters_.erase(trace_message_filter);
655 }
656
OnDisableRecordingAcked(TraceMessageFilter * trace_message_filter,const std::vector<std::string> & known_category_groups)657 void TracingControllerImpl::OnDisableRecordingAcked(
658 TraceMessageFilter* trace_message_filter,
659 const std::vector<std::string>& known_category_groups) {
660 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
661 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
662 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
663 base::Unretained(this),
664 make_scoped_refptr(trace_message_filter),
665 known_category_groups));
666 return;
667 }
668
669 // Merge known_category_groups with known_category_groups_
670 known_category_groups_.insert(known_category_groups.begin(),
671 known_category_groups.end());
672
673 if (pending_disable_recording_ack_count_ == 0)
674 return;
675
676 if (trace_message_filter &&
677 !pending_disable_recording_filters_.erase(trace_message_filter)) {
678 // The response from the specified message filter has already been received.
679 return;
680 }
681
682 if (--pending_disable_recording_ack_count_ == 1) {
683 // All acks from subprocesses have been received. Now flush the local trace.
684 // During or after this call, our OnLocalTraceDataCollected will be
685 // called with the last of the local trace data.
686 TraceLog::GetInstance()->Flush(
687 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
688 base::Unretained(this)));
689 return;
690 }
691
692 if (pending_disable_recording_ack_count_ != 0)
693 return;
694
695 OnDisableRecordingComplete();
696 }
697
OnDisableRecordingComplete()698 void TracingControllerImpl::OnDisableRecordingComplete() {
699 // All acks (including from the subprocesses and the local trace) have been
700 // received.
701 is_recording_ = false;
702
703 // Trigger callback if one is set.
704 if (!pending_get_categories_done_callback_.is_null()) {
705 pending_get_categories_done_callback_.Run(known_category_groups_);
706 pending_get_categories_done_callback_.Reset();
707 } else if (result_file_) {
708 result_file_->Close(
709 base::Bind(&TracingControllerImpl::OnResultFileClosed,
710 base::Unretained(this)));
711 }
712 }
713
OnResultFileClosed()714 void TracingControllerImpl::OnResultFileClosed() {
715 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
716
717 if (!result_file_)
718 return;
719
720 if (!pending_disable_recording_done_callback_.is_null()) {
721 pending_disable_recording_done_callback_.Run(result_file_->path());
722 pending_disable_recording_done_callback_.Reset();
723 }
724 result_file_.reset();
725 }
726
727 #if defined(OS_CHROMEOS) || defined(OS_WIN)
OnEndSystemTracingAcked(const scoped_refptr<base::RefCountedString> & events_str_ptr)728 void TracingControllerImpl::OnEndSystemTracingAcked(
729 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
731
732 if (result_file_)
733 result_file_->WriteSystemTrace(events_str_ptr);
734
735 DCHECK(!is_system_tracing_);
736 std::vector<std::string> category_groups;
737 OnDisableRecordingAcked(NULL, category_groups);
738 }
739 #endif
740
OnCaptureMonitoringSnapshotAcked(TraceMessageFilter * trace_message_filter)741 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
742 TraceMessageFilter* trace_message_filter) {
743 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
744 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
745 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
746 base::Unretained(this),
747 make_scoped_refptr(trace_message_filter)));
748 return;
749 }
750
751 if (pending_capture_monitoring_snapshot_ack_count_ == 0)
752 return;
753
754 if (trace_message_filter &&
755 !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
756 // The response from the specified message filter has already been received.
757 return;
758 }
759
760 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
761 // All acks from subprocesses have been received. Now flush the local trace.
762 // During or after this call, our OnLocalMonitoringTraceDataCollected
763 // will be called with the last of the local trace data.
764 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
765 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
766 base::Unretained(this)));
767 return;
768 }
769
770 if (pending_capture_monitoring_snapshot_ack_count_ != 0)
771 return;
772
773 if (monitoring_snapshot_file_) {
774 monitoring_snapshot_file_->Close(
775 base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed,
776 base::Unretained(this)));
777 }
778 }
779
OnMonitoringSnapshotFileClosed()780 void TracingControllerImpl::OnMonitoringSnapshotFileClosed() {
781 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
782
783 if (!monitoring_snapshot_file_)
784 return;
785
786 if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
787 pending_capture_monitoring_snapshot_done_callback_.Run(
788 monitoring_snapshot_file_->path());
789 pending_capture_monitoring_snapshot_done_callback_.Reset();
790 }
791 monitoring_snapshot_file_.reset();
792 }
793
OnTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr)794 void TracingControllerImpl::OnTraceDataCollected(
795 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
796 // OnTraceDataCollected may be called from any browser thread, either by the
797 // local event trace system or from child processes via TraceMessageFilter.
798 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
799 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
800 base::Bind(&TracingControllerImpl::OnTraceDataCollected,
801 base::Unretained(this), events_str_ptr));
802 return;
803 }
804
805 if (result_file_)
806 result_file_->Write(events_str_ptr);
807 }
808
OnMonitoringTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr)809 void TracingControllerImpl::OnMonitoringTraceDataCollected(
810 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
811 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
812 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
813 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
814 base::Unretained(this), events_str_ptr));
815 return;
816 }
817
818 if (monitoring_snapshot_file_)
819 monitoring_snapshot_file_->Write(events_str_ptr);
820 }
821
OnLocalTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr,bool has_more_events)822 void TracingControllerImpl::OnLocalTraceDataCollected(
823 const scoped_refptr<base::RefCountedString>& events_str_ptr,
824 bool has_more_events) {
825 if (events_str_ptr->data().size())
826 OnTraceDataCollected(events_str_ptr);
827
828 if (has_more_events)
829 return;
830
831 // Simulate an DisableRecordingAcked for the local trace.
832 std::vector<std::string> category_groups;
833 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
834 OnDisableRecordingAcked(NULL, category_groups);
835 }
836
OnLocalMonitoringTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr,bool has_more_events)837 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
838 const scoped_refptr<base::RefCountedString>& events_str_ptr,
839 bool has_more_events) {
840 if (events_str_ptr->data().size())
841 OnMonitoringTraceDataCollected(events_str_ptr);
842
843 if (has_more_events)
844 return;
845
846 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
847 OnCaptureMonitoringSnapshotAcked(NULL);
848 }
849
OnTraceBufferPercentFullReply(TraceMessageFilter * trace_message_filter,float percent_full)850 void TracingControllerImpl::OnTraceBufferPercentFullReply(
851 TraceMessageFilter* trace_message_filter,
852 float percent_full) {
853 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
854 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
855 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
856 base::Unretained(this),
857 make_scoped_refptr(trace_message_filter),
858 percent_full));
859 return;
860 }
861
862 if (pending_trace_buffer_percent_full_ack_count_ == 0)
863 return;
864
865 if (trace_message_filter &&
866 !pending_trace_buffer_percent_full_filters_.erase(trace_message_filter)) {
867 // The response from the specified message filter has already been received.
868 return;
869 }
870
871 maximum_trace_buffer_percent_full_ =
872 std::max(maximum_trace_buffer_percent_full_, percent_full);
873
874 if (--pending_trace_buffer_percent_full_ack_count_ == 0) {
875 // Trigger callback if one is set.
876 pending_trace_buffer_percent_full_callback_.Run(
877 maximum_trace_buffer_percent_full_);
878 pending_trace_buffer_percent_full_callback_.Reset();
879 }
880 }
881
OnWatchEventMatched()882 void TracingControllerImpl::OnWatchEventMatched() {
883 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
884 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
885 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
886 base::Unretained(this)));
887 return;
888 }
889
890 if (!watch_event_callback_.is_null())
891 watch_event_callback_.Run();
892 }
893
RegisterTracingUI(TracingUI * tracing_ui)894 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
895 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
896 tracing_uis_.insert(tracing_ui);
897 }
898
UnregisterTracingUI(TracingUI * tracing_ui)899 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
900 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui);
901 DCHECK(it != tracing_uis_.end());
902 tracing_uis_.erase(it);
903 }
904
OnMonitoringStateChanged(bool is_monitoring)905 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
906 if (is_monitoring_ == is_monitoring)
907 return;
908
909 is_monitoring_ = is_monitoring;
910 #if !defined(OS_ANDROID)
911 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
912 it != tracing_uis_.end(); it++) {
913 (*it)->OnMonitoringStateChanged(is_monitoring);
914 }
915 #endif
916 }
917
918 } // namespace content
919