summaryrefslogtreecommitdiffstats
path: root/content/browser/tracing/tracing_controller_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/tracing/tracing_controller_impl.cc')
-rw-r--r--content/browser/tracing/tracing_controller_impl.cc194
1 files changed, 156 insertions, 38 deletions
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 1c1c43a..845f1c5 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -29,10 +29,14 @@ TracingController* TracingController::GetInstance() {
}
TracingControllerImpl::TracingControllerImpl() :
- pending_end_ack_count_(0),
+ pending_disable_recording_ack_count_(0),
+ pending_capture_monitoring_snapshot_ack_count_(0),
is_recording_(false),
+ is_monitoring_(false),
category_filter_(
- base::debug::CategoryFilter::kDefaultCategoryFilterString) {
+ base::debug::CategoryFilter::kDefaultCategoryFilterString),
+ result_file_(0),
+ result_file_has_at_least_one_result_(false) {
}
TracingControllerImpl::~TracingControllerImpl() {
@@ -58,14 +62,14 @@ void TracingControllerImpl::GetCategories(
DisableRecording(TracingFileResultCallback());
}
-void TracingControllerImpl::EnableRecording(
+bool TracingControllerImpl::EnableRecording(
const base::debug::CategoryFilter& filter,
TracingController::Options options,
const EnableRecordingDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!can_enable_recording())
- return;
+ return false;
trace_options_ = TraceLog::GetInstance()->trace_options();
TraceLog::GetInstance()->SetEnabled(filter, trace_options_);
@@ -80,14 +84,15 @@ void TracingControllerImpl::EnableRecording(
if (!callback.is_null())
callback.Run();
+ return true;
}
-void TracingControllerImpl::DisableRecording(
+bool TracingControllerImpl::DisableRecording(
const TracingFileResultCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!can_end_recording())
- return;
+ if (!can_disable_recording())
+ return false;
pending_disable_recording_done_callback_ = callback;
@@ -99,18 +104,23 @@ void TracingControllerImpl::DisableRecording(
if (pending_get_categories_done_callback_.is_null()) {
base::FilePath temporary_file;
file_util::CreateTemporaryFile(&temporary_file);
- recording_result_file_.reset(new base::FilePath(temporary_file));
+ result_file_path_.reset(new base::FilePath(temporary_file));
+ result_file_ = file_util::OpenFile(*result_file_path_, "w");
+ result_file_has_at_least_one_result_ = false;
+ const char* preamble = "{\"traceEvents\": [";
+ fwrite(preamble, strlen(preamble), 1, result_file_);
}
// There could be a case where there are no child processes and filters_
// is empty. In that case we can immediately tell the subscriber that tracing
// has ended. To avoid recursive calls back to the subscriber, we will just
// use the existing asynchronous OnDisableRecordingAcked code.
- // Count myself (local trace) in pending_end_ack_count_, acked below.
- pending_end_ack_count_ = filters_.size() + 1;
+ // Count myself (local trace) in pending_disable_recording_ack_count_,
+ // acked below.
+ pending_disable_recording_ack_count_ = filters_.size() + 1;
// Handle special case of zero child processes.
- if (pending_end_ack_count_ == 1) {
+ if (pending_disable_recording_ack_count_ == 1) {
// Ack asynchronously now, because we don't have any children to wait for.
std::vector<std::string> category_groups;
TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
@@ -123,18 +133,50 @@ void TracingControllerImpl::DisableRecording(
for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
it->get()->SendEndTracing();
}
+ return true;
}
-void TracingControllerImpl::EnableMonitoring(
+bool TracingControllerImpl::EnableMonitoring(
const base::debug::CategoryFilter& filter,
TracingController::Options options,
const EnableMonitoringDoneCallback& callback) {
- NOTIMPLEMENTED();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_enable_monitoring())
+ return false;
+ is_monitoring_ = true;
+
+ int monitoring_tracing_options = 0;
+ if (options & ENABLE_SAMPLING)
+ monitoring_tracing_options |= base::debug::TraceLog::MONITOR_SAMPLING;
+
+ // Notify all child processes.
+ for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
+ it->get()->SendEnableMonitoring(filter.ToString(),
+ base::debug::TraceLog::Options(monitoring_tracing_options));
+ }
+
+ if (!callback.is_null())
+ callback.Run();
+ return true;
}
-void TracingControllerImpl::DisableMonitoring(
+bool TracingControllerImpl::DisableMonitoring(
const DisableMonitoringDoneCallback& callback) {
- NOTIMPLEMENTED();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_disable_monitoring())
+ return false;
+ is_monitoring_ = false;
+
+ // Notify all child processes.
+ for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
+ it->get()->SendDisableMonitoring();
+ }
+
+ if (!callback.is_null())
+ callback.Run();
+ return true;
}
void TracingControllerImpl::GetMonitoringStatus(
@@ -144,9 +186,43 @@ void TracingControllerImpl::GetMonitoringStatus(
NOTIMPLEMENTED();
}
-void TracingControllerImpl::CaptureCurrentMonitoringSnapshot(
+void TracingControllerImpl::CaptureMonitoringSnapshot(
const TracingFileResultCallback& callback) {
- NOTIMPLEMENTED();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_disable_monitoring())
+ return;
+
+ pending_capture_monitoring_snapshot_done_callback_ = callback;
+
+ base::FilePath temporary_file;
+ file_util::CreateTemporaryFile(&temporary_file);
+ result_file_path_.reset(new base::FilePath(temporary_file));
+ result_file_ = file_util::OpenFile(*result_file_path_, "w");
+ result_file_has_at_least_one_result_ = false;
+ const char* preamble = "{\"traceEvents\": [";
+ fwrite(preamble, strlen(preamble), 1, result_file_);
+
+ // There could be a case where there are no child processes and filters_
+ // is empty. In that case we can immediately tell the subscriber that tracing
+ // has ended. To avoid recursive calls back to the subscriber, we will just
+ // use the existing asynchronous OnCaptureMonitoringSnapshotAcked code.
+ // Count myself in pending_capture_monitoring_snapshot_ack_count_,
+ // acked below.
+ pending_capture_monitoring_snapshot_ack_count_ = filters_.size() + 1;
+
+ // Handle special case of zero child processes.
+ if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
+ // Ack asynchronously now, because we don't have any children to wait for.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
+ base::Unretained(this)));
+ }
+
+ // Notify all child processes.
+ for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
+ it->get()->SendCaptureMonitoringSnapshot();
+ }
}
void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) {
@@ -158,7 +234,7 @@ void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) {
}
filters_.insert(filter);
- if (is_recording_enabled()) {
+ if (can_disable_recording()) {
std::string cf_str = category_filter_.ToString();
filter->SendBeginTracing(cf_str, trace_options_);
}
@@ -188,10 +264,10 @@ void TracingControllerImpl::OnDisableRecordingAcked(
known_category_groups_.insert(known_category_groups.begin(),
known_category_groups.end());
- if (pending_end_ack_count_ == 0)
+ if (pending_disable_recording_ack_count_ == 0)
return;
- if (--pending_end_ack_count_ == 1) {
+ if (--pending_disable_recording_ack_count_ == 1) {
// All acks from subprocesses have been received. Now flush the local trace.
// During or after this call, our OnLocalTraceDataCollected will be
// called with the last of the local trace data.
@@ -200,7 +276,7 @@ void TracingControllerImpl::OnDisableRecordingAcked(
base::Unretained(this)));
}
- if (pending_end_ack_count_ != 0)
+ if (pending_disable_recording_ack_count_ != 0)
return;
// All acks (including from the subprocesses and the local trace) have been
@@ -211,17 +287,48 @@ void TracingControllerImpl::OnDisableRecordingAcked(
if (!pending_get_categories_done_callback_.is_null()) {
pending_get_categories_done_callback_.Run(known_category_groups_);
pending_get_categories_done_callback_.Reset();
- } else {
- OnEndTracingComplete();
+ } else if (!pending_disable_recording_done_callback_.is_null()) {
+ const char* trailout = "]}";
+ fwrite(trailout, strlen(trailout), 1, result_file_);
+ file_util::CloseFile(result_file_);
+ result_file_ = 0;
+ pending_disable_recording_done_callback_.Run(result_file_path_.Pass());
+ pending_disable_recording_done_callback_.Reset();
}
}
-void TracingControllerImpl::OnEndTracingComplete() {
- if (pending_disable_recording_done_callback_.is_null())
+void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked() {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
+ base::Unretained(this)));
+ return;
+ }
+
+ if (pending_capture_monitoring_snapshot_ack_count_ == 0)
return;
- pending_disable_recording_done_callback_.Run(recording_result_file_.Pass());
- pending_disable_recording_done_callback_.Reset();
+ if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
+ // All acks from subprocesses have been received. Now flush the local trace.
+ // During or after this call, our OnLocalMonitoringTraceDataCollected
+ // will be called with the last of the local trace data.
+ TraceLog::GetInstance()->FlushButLeaveBufferIntact(
+ base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
+ base::Unretained(this)));
+ }
+
+ if (pending_capture_monitoring_snapshot_ack_count_ != 0)
+ return;
+
+ if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
+ const char* trailout = "]}";
+ fwrite(trailout, strlen(trailout), 1, result_file_);
+ file_util::CloseFile(result_file_);
+ result_file_ = 0;
+ pending_capture_monitoring_snapshot_done_callback_.Run(
+ result_file_path_.Pass());
+ pending_capture_monitoring_snapshot_done_callback_.Reset();
+ }
}
void TracingControllerImpl::OnTraceDataCollected(
@@ -239,17 +346,15 @@ void TracingControllerImpl::OnTraceDataCollected(
if (!pending_get_categories_done_callback_.is_null())
return;
- std::string javascript;
- javascript.reserve(events_str_ptr->size() * 2);
- base::JsonDoubleQuote(events_str_ptr->data(), false, &javascript);
-
- // Intentionally append a , to the traceData. This technically causes all
- // traceData that we pass back to JS to end with a comma, but that is
- // actually something the JS side strips away anyway
- javascript.append(",");
-
- file_util::WriteFile(*recording_result_file_,
- javascript.c_str(), javascript.length());
+ // If there is already a result in the file, then put a commma
+ // before the next batch of results.
+ if (result_file_has_at_least_one_result_) {
+ fwrite(",", 1, 1, result_file_);
+ } else {
+ result_file_has_at_least_one_result_ = true;
+ }
+ fwrite(events_str_ptr->data().c_str(), events_str_ptr->data().size(), 1,
+ result_file_);
}
void TracingControllerImpl::OnLocalTraceDataCollected(
@@ -267,4 +372,17 @@ void TracingControllerImpl::OnLocalTraceDataCollected(
OnDisableRecordingAcked(category_groups);
}
+void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& events_str_ptr,
+ bool has_more_events) {
+ if (events_str_ptr->data().size())
+ OnTraceDataCollected(events_str_ptr);
+
+ if (has_more_events)
+ return;
+
+ // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
+ OnCaptureMonitoringSnapshotAcked();
+}
+
} // namespace content