• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 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 
5 #include "content/browser/tracing/tracing_controller_impl.h"
6 
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9 #include "base/file_util.h"
10 #include "base/json/string_escape.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "content/browser/tracing/trace_message_filter.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 using base::debug::TraceLog;
18 
19 namespace content {
20 
21 namespace {
22 
23 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
24     LAZY_INSTANCE_INITIALIZER;
25 
26 }  // namespace
27 
GetInstance()28 TracingController* TracingController::GetInstance() {
29   return TracingControllerImpl::GetInstance();
30 }
31 
32 class TracingControllerImpl::ResultFile {
33  public:
34   explicit ResultFile(const base::FilePath& path);
Write(const scoped_refptr<base::RefCountedString> & events_str_ptr)35   void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) {
36     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
37         base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
38                    base::Unretained(this), events_str_ptr));
39   }
Close(const base::Closure & callback)40   void Close(const base::Closure& callback) {
41     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
42         base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
43                    base::Unretained(this), callback));
44   }
path() const45   const base::FilePath& path() const { return path_; }
46 
47  private:
48   void OpenTask();
49   void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr);
50   void CloseTask(const base::Closure& callback);
51 
52   FILE* file_;
53   base::FilePath path_;
54   bool has_at_least_one_result_;
55 
56   DISALLOW_COPY_AND_ASSIGN(ResultFile);
57 };
58 
ResultFile(const base::FilePath & path)59 TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path)
60     : file_(NULL),
61       path_(path),
62       has_at_least_one_result_(false) {
63   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
64       base::Bind(&TracingControllerImpl::ResultFile::OpenTask,
65                  base::Unretained(this)));
66 }
67 
OpenTask()68 void TracingControllerImpl::ResultFile::OpenTask() {
69   if (path_.empty())
70     base::CreateTemporaryFile(&path_);
71   file_ = base::OpenFile(path_, "w");
72   if (!file_) {
73     LOG(ERROR) << "Failed to open " << path_.value();
74     return;
75   }
76   const char* preamble = "{\"traceEvents\": [";
77   size_t written = fwrite(preamble, strlen(preamble), 1, file_);
78   DCHECK(written == 1);
79 }
80 
WriteTask(const scoped_refptr<base::RefCountedString> & events_str_ptr)81 void TracingControllerImpl::ResultFile::WriteTask(
82     const scoped_refptr<base::RefCountedString>& events_str_ptr) {
83   if (!file_)
84     return;
85 
86   // If there is already a result in the file, then put a commma
87   // before the next batch of results.
88   if (has_at_least_one_result_) {
89     size_t written = fwrite(",", 1, 1, file_);
90     DCHECK(written == 1);
91   }
92   has_at_least_one_result_ = true;
93   size_t written = fwrite(events_str_ptr->data().c_str(),
94                           events_str_ptr->data().size(), 1,
95                           file_);
96   DCHECK(written == 1);
97 }
98 
CloseTask(const base::Closure & callback)99 void TracingControllerImpl::ResultFile::CloseTask(
100     const base::Closure& callback) {
101   if (!file_)
102     return;
103 
104   const char* trailout = "]}";
105   size_t written = fwrite(trailout, strlen(trailout), 1, file_);
106   DCHECK(written == 1);
107   base::CloseFile(file_);
108   file_ = NULL;
109 
110   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
111 }
112 
113 
TracingControllerImpl()114 TracingControllerImpl::TracingControllerImpl() :
115     pending_disable_recording_ack_count_(0),
116     pending_capture_monitoring_snapshot_ack_count_(0),
117     pending_trace_buffer_percent_full_ack_count_(0),
118     maximum_trace_buffer_percent_full_(0),
119     // Tracing may have been enabled by ContentMainRunner if kTraceStartup
120     // is specified in command line.
121     is_recording_(TraceLog::GetInstance()->IsEnabled()),
122     is_monitoring_(false) {
123 }
124 
~TracingControllerImpl()125 TracingControllerImpl::~TracingControllerImpl() {
126   // This is a Leaky instance.
127   NOTREACHED();
128 }
129 
GetInstance()130 TracingControllerImpl* TracingControllerImpl::GetInstance() {
131   return g_controller.Pointer();
132 }
133 
GetCategories(const GetCategoriesDoneCallback & callback)134 bool TracingControllerImpl::GetCategories(
135     const GetCategoriesDoneCallback& callback) {
136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137 
138   // Known categories come back from child processes with the EndTracingAck
139   // message. So to get known categories, just begin and end tracing immediately
140   // afterwards. This will ping all the child processes for categories.
141   pending_get_categories_done_callback_ = callback;
142   if (!EnableRecording("*", TracingController::Options(),
143                        EnableRecordingDoneCallback())) {
144     pending_get_categories_done_callback_.Reset();
145     return false;
146   }
147 
148   bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback());
149   DCHECK(ok);
150   return true;
151 }
152 
EnableRecording(const std::string & category_filter,TracingController::Options options,const EnableRecordingDoneCallback & callback)153 bool TracingControllerImpl::EnableRecording(
154     const std::string& category_filter,
155     TracingController::Options options,
156     const EnableRecordingDoneCallback& callback) {
157   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158 
159   if (!can_enable_recording())
160     return false;
161 
162 #if defined(OS_ANDROID)
163   if (pending_get_categories_done_callback_.is_null())
164     TraceLog::GetInstance()->AddClockSyncMetadataEvent();
165 #endif
166 
167   TraceLog::Options trace_options = (options & RECORD_CONTINUOUSLY) ?
168       TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL;
169   if (options & ENABLE_SAMPLING) {
170     trace_options = static_cast<TraceLog::Options>(
171         trace_options | TraceLog::ENABLE_SAMPLING);
172   }
173   // TODO(haraken): How to handle ENABLE_SYSTRACE?
174 
175   TraceLog::GetInstance()->SetEnabled(
176       base::debug::CategoryFilter(category_filter), trace_options);
177   is_recording_ = true;
178 
179   // Notify all child processes.
180   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
181       it != trace_message_filters_.end(); ++it) {
182     it->get()->SendBeginTracing(category_filter, trace_options);
183   }
184 
185   if (!callback.is_null())
186     callback.Run();
187   return true;
188 }
189 
DisableRecording(const base::FilePath & result_file_path,const TracingFileResultCallback & callback)190 bool TracingControllerImpl::DisableRecording(
191     const base::FilePath& result_file_path,
192     const TracingFileResultCallback& callback) {
193   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
194 
195   if (!can_disable_recording())
196     return false;
197 
198   pending_disable_recording_done_callback_ = callback;
199 
200   // Disable local trace early to avoid traces during end-tracing process from
201   // interfering with the process.
202   TraceLog::GetInstance()->SetDisabled();
203 
204 #if defined(OS_ANDROID)
205   if (pending_get_categories_done_callback_.is_null())
206     TraceLog::GetInstance()->AddClockSyncMetadataEvent();
207 #endif
208 
209   if (!callback.is_null() || !result_file_path.empty())
210     result_file_.reset(new ResultFile(result_file_path));
211 
212   // Count myself (local trace) in pending_disable_recording_ack_count_,
213   // acked below.
214   pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
215 
216   // Handle special case of zero child processes by immediately telling the
217   // caller that tracing has ended. Use asynchronous OnDisableRecordingAcked
218   // to avoid recursive call back to the caller.
219   if (pending_disable_recording_ack_count_ == 1) {
220     // Ack asynchronously now, because we don't have any children to wait for.
221     std::vector<std::string> category_groups;
222     TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
223     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
224         base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
225                    base::Unretained(this), category_groups));
226   }
227 
228   // Notify all child processes.
229   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
230       it != trace_message_filters_.end(); ++it) {
231     it->get()->SendEndTracing();
232   }
233   return true;
234 }
235 
EnableMonitoring(const std::string & category_filter,TracingController::Options options,const EnableMonitoringDoneCallback & callback)236 bool TracingControllerImpl::EnableMonitoring(
237     const std::string& category_filter,
238     TracingController::Options options,
239     const EnableMonitoringDoneCallback& callback) {
240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
241 
242   if (!can_enable_monitoring())
243     return false;
244   is_monitoring_ = true;
245 
246 #if defined(OS_ANDROID)
247   TraceLog::GetInstance()->AddClockSyncMetadataEvent();
248 #endif
249 
250   int monitoring_tracing_options = 0;
251   if (options & ENABLE_SAMPLING)
252     monitoring_tracing_options |= base::debug::TraceLog::MONITOR_SAMPLING;
253 
254   TraceLog::GetInstance()->SetEnabled(
255       base::debug::CategoryFilter(category_filter),
256       static_cast<TraceLog::Options>(monitoring_tracing_options));
257 
258   // Notify all child processes.
259   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
260       it != trace_message_filters_.end(); ++it) {
261     it->get()->SendEnableMonitoring(category_filter,
262         static_cast<TraceLog::Options>(monitoring_tracing_options));
263   }
264 
265   if (!callback.is_null())
266     callback.Run();
267   return true;
268 }
269 
DisableMonitoring(const DisableMonitoringDoneCallback & callback)270 bool TracingControllerImpl::DisableMonitoring(
271     const DisableMonitoringDoneCallback& callback) {
272   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
273 
274   if (!can_disable_monitoring())
275     return false;
276   is_monitoring_ = false;
277 
278   TraceLog::GetInstance()->SetDisabled();
279 
280   // Notify all child processes.
281   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
282       it != trace_message_filters_.end(); ++it) {
283     it->get()->SendDisableMonitoring();
284   }
285 
286   if (!callback.is_null())
287     callback.Run();
288   return true;
289 }
290 
GetMonitoringStatus(bool * out_enabled,std::string * out_category_filter,TracingController::Options * out_options)291 void TracingControllerImpl::GetMonitoringStatus(
292     bool* out_enabled,
293     std::string* out_category_filter,
294     TracingController::Options* out_options) {
295   NOTIMPLEMENTED();
296 }
297 
CaptureMonitoringSnapshot(const base::FilePath & result_file_path,const TracingFileResultCallback & callback)298 bool TracingControllerImpl::CaptureMonitoringSnapshot(
299     const base::FilePath& result_file_path,
300     const TracingFileResultCallback& callback) {
301   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
302 
303   if (!can_disable_monitoring())
304     return false;
305 
306   if (callback.is_null() && result_file_path.empty())
307     return false;
308 
309   pending_capture_monitoring_snapshot_done_callback_ = callback;
310   monitoring_snapshot_file_.reset(new ResultFile(result_file_path));
311 
312   // Count myself in pending_capture_monitoring_snapshot_ack_count_,
313   // acked below.
314   pending_capture_monitoring_snapshot_ack_count_ =
315       trace_message_filters_.size() + 1;
316 
317   // Handle special case of zero child processes by immediately telling the
318   // caller that capturing snapshot has ended. Use asynchronous
319   // OnCaptureMonitoringSnapshotAcked to avoid recursive call back to the
320   // caller.
321   if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
322     // Ack asynchronously now, because we don't have any children to wait for.
323     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
324         base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
325                    base::Unretained(this)));
326   }
327 
328   // Notify all child processes.
329   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
330       it != trace_message_filters_.end(); ++it) {
331     it->get()->SendCaptureMonitoringSnapshot();
332   }
333 
334 #if defined(OS_ANDROID)
335   TraceLog::GetInstance()->AddClockSyncMetadataEvent();
336 #endif
337 
338   return true;
339 }
340 
GetTraceBufferPercentFull(const GetTraceBufferPercentFullCallback & callback)341 bool TracingControllerImpl::GetTraceBufferPercentFull(
342     const GetTraceBufferPercentFullCallback& callback) {
343   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
344 
345   if (!can_get_trace_buffer_percent_full() || callback.is_null())
346     return false;
347 
348   pending_trace_buffer_percent_full_callback_ = callback;
349 
350   // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below.
351   pending_trace_buffer_percent_full_ack_count_ =
352       trace_message_filters_.size() + 1;
353   maximum_trace_buffer_percent_full_ = 0;
354 
355   // Handle special case of zero child processes.
356   if (pending_trace_buffer_percent_full_ack_count_ == 1) {
357     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
358         base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
359                    base::Unretained(this),
360                    TraceLog::GetInstance()->GetBufferPercentFull()));
361   }
362 
363   // Notify all child processes.
364   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
365       it != trace_message_filters_.end(); ++it) {
366     it->get()->SendGetTraceBufferPercentFull();
367   }
368   return true;
369 }
370 
SetWatchEvent(const std::string & category_name,const std::string & event_name,const WatchEventCallback & callback)371 bool TracingControllerImpl::SetWatchEvent(
372     const std::string& category_name,
373     const std::string& event_name,
374     const WatchEventCallback& callback) {
375   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
376 
377   if (callback.is_null())
378     return false;
379 
380   watch_category_name_ = category_name;
381   watch_event_name_ = event_name;
382   watch_event_callback_ = callback;
383 
384   TraceLog::GetInstance()->SetWatchEvent(
385       category_name, event_name,
386       base::Bind(&TracingControllerImpl::OnWatchEventMatched,
387                  base::Unretained(this)));
388 
389   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
390       it != trace_message_filters_.end(); ++it) {
391     it->get()->SendSetWatchEvent(category_name, event_name);
392   }
393   return true;
394 }
395 
CancelWatchEvent()396 bool TracingControllerImpl::CancelWatchEvent() {
397   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
398 
399   if (!can_cancel_watch_event())
400     return false;
401 
402   for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin();
403       it != trace_message_filters_.end(); ++it) {
404     it->get()->SendCancelWatchEvent();
405   }
406 
407   watch_event_callback_.Reset();
408   return true;
409 }
410 
AddTraceMessageFilter(TraceMessageFilter * trace_message_filter)411 void TracingControllerImpl::AddTraceMessageFilter(
412     TraceMessageFilter* trace_message_filter) {
413   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
414     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
415         base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
416                    base::Unretained(this),
417                    make_scoped_refptr(trace_message_filter)));
418     return;
419   }
420 
421   trace_message_filters_.insert(trace_message_filter);
422   if (can_cancel_watch_event()) {
423     trace_message_filter->SendSetWatchEvent(watch_category_name_,
424                                             watch_event_name_);
425   }
426   if (can_disable_recording()) {
427     trace_message_filter->SendBeginTracing(
428         TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(),
429         TraceLog::GetInstance()->trace_options());
430   }
431 }
432 
RemoveTraceMessageFilter(TraceMessageFilter * trace_message_filter)433 void TracingControllerImpl::RemoveTraceMessageFilter(
434     TraceMessageFilter* trace_message_filter) {
435   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
436     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
437         base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
438                    base::Unretained(this),
439                    make_scoped_refptr(trace_message_filter)));
440     return;
441   }
442 
443   trace_message_filters_.erase(trace_message_filter);
444 }
445 
OnDisableRecordingAcked(const std::vector<std::string> & known_category_groups)446 void TracingControllerImpl::OnDisableRecordingAcked(
447     const std::vector<std::string>& known_category_groups) {
448   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
449     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
450         base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
451                    base::Unretained(this), known_category_groups));
452     return;
453   }
454 
455   // Merge known_category_groups with known_category_groups_
456   known_category_groups_.insert(known_category_groups.begin(),
457                                 known_category_groups.end());
458 
459   if (pending_disable_recording_ack_count_ == 0)
460     return;
461 
462   if (--pending_disable_recording_ack_count_ == 1) {
463     // All acks from subprocesses have been received. Now flush the local trace.
464     // During or after this call, our OnLocalTraceDataCollected will be
465     // called with the last of the local trace data.
466     TraceLog::GetInstance()->Flush(
467         base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
468                    base::Unretained(this)));
469     return;
470   }
471 
472   if (pending_disable_recording_ack_count_ != 0)
473     return;
474 
475   // All acks (including from the subprocesses and the local trace) have been
476   // received.
477   is_recording_ = false;
478 
479   // Trigger callback if one is set.
480   if (!pending_get_categories_done_callback_.is_null()) {
481     pending_get_categories_done_callback_.Run(known_category_groups_);
482     pending_get_categories_done_callback_.Reset();
483   } else if (result_file_) {
484     result_file_->Close(
485         base::Bind(&TracingControllerImpl::OnResultFileClosed,
486                    base::Unretained(this)));
487   }
488 }
489 
OnResultFileClosed()490 void TracingControllerImpl::OnResultFileClosed() {
491   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
492 
493   if (!result_file_)
494     return;
495 
496   if (!pending_disable_recording_done_callback_.is_null()) {
497     pending_disable_recording_done_callback_.Run(result_file_->path());
498     pending_disable_recording_done_callback_.Reset();
499   }
500   result_file_.reset();
501 }
502 
OnCaptureMonitoringSnapshotAcked()503 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked() {
504   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
505     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
506         base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
507                    base::Unretained(this)));
508     return;
509   }
510 
511   if (pending_capture_monitoring_snapshot_ack_count_ == 0)
512     return;
513 
514   if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
515     // All acks from subprocesses have been received. Now flush the local trace.
516     // During or after this call, our OnLocalMonitoringTraceDataCollected
517     // will be called with the last of the local trace data.
518     TraceLog::GetInstance()->FlushButLeaveBufferIntact(
519         base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
520                    base::Unretained(this)));
521     return;
522   }
523 
524   if (pending_capture_monitoring_snapshot_ack_count_ != 0)
525     return;
526 
527   if (monitoring_snapshot_file_) {
528     monitoring_snapshot_file_->Close(
529         base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed,
530                    base::Unretained(this)));
531   }
532 }
533 
OnMonitoringSnapshotFileClosed()534 void TracingControllerImpl::OnMonitoringSnapshotFileClosed() {
535   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
536 
537   if (!monitoring_snapshot_file_)
538     return;
539 
540   if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
541     pending_capture_monitoring_snapshot_done_callback_.Run(
542         monitoring_snapshot_file_->path());
543     pending_capture_monitoring_snapshot_done_callback_.Reset();
544   }
545   monitoring_snapshot_file_.reset();
546 }
547 
OnTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr)548 void TracingControllerImpl::OnTraceDataCollected(
549     const scoped_refptr<base::RefCountedString>& events_str_ptr) {
550   // OnTraceDataCollected may be called from any browser thread, either by the
551   // local event trace system or from child processes via TraceMessageFilter.
552   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
553     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
554         base::Bind(&TracingControllerImpl::OnTraceDataCollected,
555                    base::Unretained(this), events_str_ptr));
556     return;
557   }
558 
559   if (result_file_)
560     result_file_->Write(events_str_ptr);
561 }
562 
OnMonitoringTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr)563 void TracingControllerImpl::OnMonitoringTraceDataCollected(
564     const scoped_refptr<base::RefCountedString>& events_str_ptr) {
565   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
566     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
567         base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
568                    base::Unretained(this), events_str_ptr));
569     return;
570   }
571 
572   if (monitoring_snapshot_file_)
573     monitoring_snapshot_file_->Write(events_str_ptr);
574 }
575 
OnLocalTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr,bool has_more_events)576 void TracingControllerImpl::OnLocalTraceDataCollected(
577     const scoped_refptr<base::RefCountedString>& events_str_ptr,
578     bool has_more_events) {
579   if (events_str_ptr->data().size())
580     OnTraceDataCollected(events_str_ptr);
581 
582   if (has_more_events)
583     return;
584 
585   // Simulate an DisableRecordingAcked for the local trace.
586   std::vector<std::string> category_groups;
587   TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
588   OnDisableRecordingAcked(category_groups);
589 }
590 
OnLocalMonitoringTraceDataCollected(const scoped_refptr<base::RefCountedString> & events_str_ptr,bool has_more_events)591 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
592     const scoped_refptr<base::RefCountedString>& events_str_ptr,
593     bool has_more_events) {
594   if (events_str_ptr->data().size())
595     OnMonitoringTraceDataCollected(events_str_ptr);
596 
597   if (has_more_events)
598     return;
599 
600   // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
601   OnCaptureMonitoringSnapshotAcked();
602 }
603 
OnTraceBufferPercentFullReply(float percent_full)604 void TracingControllerImpl::OnTraceBufferPercentFullReply(float percent_full) {
605   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
606     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
607         base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
608                    base::Unretained(this), percent_full));
609     return;
610   }
611 
612   if (pending_trace_buffer_percent_full_ack_count_ == 0)
613     return;
614 
615   maximum_trace_buffer_percent_full_ =
616       std::max(maximum_trace_buffer_percent_full_, percent_full);
617 
618   if (--pending_trace_buffer_percent_full_ack_count_ == 0) {
619     // Trigger callback if one is set.
620     pending_trace_buffer_percent_full_callback_.Run(
621         maximum_trace_buffer_percent_full_);
622     pending_trace_buffer_percent_full_callback_.Reset();
623   }
624 
625   if (pending_trace_buffer_percent_full_ack_count_ == 1) {
626     // The last ack represents local trace, so we need to ack it now. Note that
627     // this code only executes if there were child processes.
628     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
629         base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
630                    base::Unretained(this),
631                    TraceLog::GetInstance()->GetBufferPercentFull()));
632   }
633 }
634 
OnWatchEventMatched()635 void TracingControllerImpl::OnWatchEventMatched() {
636   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
637     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
638         base::Bind(&TracingControllerImpl::OnWatchEventMatched,
639                    base::Unretained(this)));
640     return;
641   }
642 
643   if (!watch_event_callback_.is_null())
644     watch_event_callback_.Run();
645 }
646 
647 }  // namespace content
648