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