Chromium Code Reviews| Index: content/browser/tracing/tracing_controller_impl.cc |
| diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc |
| index ca480c70638cf829cc292c7cb2a683d7bc5474cb..765ac2bee1b17335626e33f899fdc1c36c0af168 100644 |
| --- a/content/browser/tracing/tracing_controller_impl.cc |
| +++ b/content/browser/tracing/tracing_controller_impl.cc |
| @@ -34,133 +34,134 @@ namespace { |
| base::LazyInstance<TracingControllerImpl>::Leaky g_controller = |
| LAZY_INSTANCE_INITIALIZER; |
| -} // namespace |
| - |
| -TracingController* TracingController::GetInstance() { |
| - return TracingControllerImpl::GetInstance(); |
| -} |
| - |
| -class TracingControllerImpl::ResultFile { |
| +class FileTraceDataSink : public TracingController::TraceDataSink { |
| public: |
| - explicit ResultFile(const base::FilePath& path); |
| - void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
| + explicit FileTraceDataSink( |
| + const base::FilePath& trace_file_path, const base::Closure& callback) |
| + : file_path_(trace_file_path), |
| + completion_callback_(callback), |
| + file_(NULL) { |
| + } |
| + |
| + virtual void AddTraceChunk(const std::string& chunk) OVERRIDE { |
| + std::string tmp = chunk; |
| + scoped_refptr<base::RefCountedString> chunk_ptr = |
| + base::RefCountedString::TakeString(&tmp); |
| BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| - base::Bind(&TracingControllerImpl::ResultFile::WriteTask, |
| - base::Unretained(this), events_str_ptr)); |
| + base::Bind(&FileTraceDataSink::AddTraceChunkOnFileThread, |
| + base::Unretained(this), chunk_ptr)); |
| } |
| - void Close(const base::Closure& callback) { |
| + virtual void SetSystemTrace(const std::string& data) OVERRIDE { |
| + system_trace_ = data; |
| + } |
| + virtual void Close() OVERRIDE { |
| BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| - base::Bind(&TracingControllerImpl::ResultFile::CloseTask, |
| - base::Unretained(this), callback)); |
| - } |
| - void WriteSystemTrace( |
| - const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
| - BrowserThread::PostTask( |
| - BrowserThread::FILE, |
| - FROM_HERE, |
| - base::Bind(&TracingControllerImpl::ResultFile::WriteSystemTraceTask, |
| - base::Unretained(this), events_str_ptr)); |
| + base::Bind(&FileTraceDataSink::CloseOnFileThread, |
| + base::Unretained(this))); |
| } |
| - const base::FilePath& path() const { return path_; } |
| - |
| private: |
| - void OpenTask(); |
| - void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr); |
| - void WriteSystemTraceTask( |
| - const scoped_refptr<base::RefCountedString>& events_str_ptr); |
| - void CloseTask(const base::Closure& callback); |
| + virtual ~FileTraceDataSink() {} |
| + |
| + void AddTraceChunkOnFileThread( |
| + const scoped_refptr<base::RefCountedString> chunk) { |
| + if (!OpenFileIfNeededOnFileThread()) |
| + return; |
| + fwrite(chunk->data().c_str(), strlen(chunk->data().c_str()), 1, file_); |
| + } |
| + |
| + bool OpenFileIfNeededOnFileThread() { |
| + if (file_) |
| + return true; |
| + file_ = base::OpenFile(file_path_, "w"); |
| + if (!file_) { |
| + LOG(ERROR) << "Failed to open " << file_path_.value(); |
| + return false; |
| + } |
| + const char preamble[] = "{\"traceEvents\": ["; |
| + fwrite(preamble, strlen(preamble), 1, file_); |
| + return true; |
| + } |
| + |
| + void CloseOnFileThread() { |
| + if (OpenFileIfNeededOnFileThread()) { |
| + fputc(']', file_); |
| + if (!system_trace_.empty()) { |
| + const char systemTraceEvents[] = ",\"systemTraceEvents\":["; |
| + fwrite(systemTraceEvents, strlen(systemTraceEvents), 1, file_); |
| + fwrite(system_trace_.c_str(), strlen(system_trace_.c_str()), 1, file_); |
| + fputc(']', file_); |
| + } |
| + fputc('}', file_); |
| + base::CloseFile(file_); |
| + } |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&FileTraceDataSink::FinalizeOnUIThread, |
| + base::Unretained(this))); |
| + } |
| - FILE* file_; |
| - base::FilePath path_; |
| - bool has_at_least_one_result_; |
| - scoped_refptr<base::RefCountedString> system_trace_; |
| + void FinalizeOnUIThread() { |
| + completion_callback_.Run(); |
| + delete this; |
| + } |
| - DISALLOW_COPY_AND_ASSIGN(ResultFile); |
| + base::FilePath file_path_; |
| + base::Closure completion_callback_; |
| + FILE* file_; |
| + std::string system_trace_; |
| }; |
| -TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path) |
| - : file_(NULL), |
| - path_(path), |
| - has_at_least_one_result_(false) { |
| - BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| - base::Bind(&TracingControllerImpl::ResultFile::OpenTask, |
| - base::Unretained(this))); |
| -} |
| +class StringTraceDataSink : public TracingController::TraceDataSink { |
| + public: |
| + typedef base::Callback<void(base::RefCountedMemory*)> |
| + CompletionCallback; |
| -void TracingControllerImpl::ResultFile::OpenTask() { |
| - if (path_.empty()) |
| - base::CreateTemporaryFile(&path_); |
| - file_ = base::OpenFile(path_, "w"); |
| - if (!file_) { |
| - LOG(ERROR) << "Failed to open " << path_.value(); |
| - return; |
| + explicit StringTraceDataSink(CompletionCallback callback) |
| + : completion_callback_(callback) { |
| } |
| - const char* preamble = "{\"traceEvents\": ["; |
| - size_t written = fwrite(preamble, strlen(preamble), 1, file_); |
| - DCHECK(written == 1); |
| -} |
| -void TracingControllerImpl::ResultFile::WriteTask( |
| - const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
| - if (!file_ || !events_str_ptr->data().size()) |
| - return; |
| - |
| - // If there is already a result in the file, then put a comma |
| - // before the next batch of results. |
| - if (has_at_least_one_result_) { |
| - size_t written = fwrite(",", 1, 1, file_); |
| - DCHECK(written == 1); |
| + // TracingController::TraceDataSink implementation |
| + virtual void AddTraceChunk(const std::string& chunk) OVERRIDE { |
| + if (!trace_.empty()) |
| + trace_ += ","; |
| + trace_ += chunk; |
| } |
| - has_at_least_one_result_ = true; |
| - size_t written = fwrite(events_str_ptr->data().c_str(), |
| - events_str_ptr->data().size(), 1, |
| - file_); |
| - DCHECK(written == 1); |
| -} |
| - |
| -void TracingControllerImpl::ResultFile::WriteSystemTraceTask( |
| - const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
| - system_trace_ = events_str_ptr; |
| -} |
| - |
| -void TracingControllerImpl::ResultFile::CloseTask( |
| - const base::Closure& callback) { |
| - if (!file_) |
| - return; |
| - |
| - const char* trailevents = "]"; |
| - size_t written = fwrite(trailevents, strlen(trailevents), 1, file_); |
| - DCHECK(written == 1); |
| + virtual void SetSystemTrace(const std::string& data) OVERRIDE { |
| + system_trace_ = data; |
| + } |
| + virtual void Close() OVERRIDE { |
| + std::string result = "{\"traceEvents\":[" + trace_ + "]"; |
| + if (!system_trace_.empty()) |
| + result += ",\"systemTraceEvents\":[" + system_trace_ + "]"; |
| + result += "}"; |
| - if (system_trace_.get()) { |
| -#if defined(OS_WIN) |
| - // The Windows kernel events are kept into a JSon format stored as string |
| - // and must not be escaped. |
| - std::string json_string = system_trace_->data(); |
| -#else |
| - std::string json_string = base::GetQuotedJSONString(system_trace_->data()); |
| -#endif |
| + completion_callback_.Run(base::RefCountedString::TakeString(&result)); |
| + delete this; |
|
dsinclair
2014/09/04 18:03:12
I'm not a fan of the delete this on the Close() me
|
| + } |
| - const char* systemTraceHead = ",\n\"systemTraceEvents\": "; |
| - written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_); |
| - DCHECK(written == 1); |
| + private: |
| + virtual ~StringTraceDataSink() {} |
| - written = fwrite(json_string.data(), json_string.size(), 1, file_); |
| - DCHECK(written == 1); |
| + std::string trace_; |
| + std::string system_trace_; |
| + CompletionCallback completion_callback_; |
| +}; |
| - system_trace_ = NULL; |
| - } |
| +} // namespace |
| - const char* trailout = "}"; |
| - written = fwrite(trailout, strlen(trailout), 1, file_); |
| - DCHECK(written == 1); |
| - base::CloseFile(file_); |
| - file_ = NULL; |
| +TracingController* TracingController::GetInstance() { |
| + return TracingControllerImpl::GetInstance(); |
| +} |
| - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); |
| +TracingController::TraceDataSink* TracingControllerImpl::CreateStringSink( |
| + const base::Callback<void(base::RefCountedMemory*)>& callback) { |
| + return new StringTraceDataSink(callback); |
| } |
| +TracingController::TraceDataSink* TracingControllerImpl::CreateFileSink( |
| + const base::FilePath& file_path, const base::Closure& callback) { |
| + return new FileTraceDataSink(file_path, callback); |
| +} |
| TracingControllerImpl::TracingControllerImpl() : |
| pending_disable_recording_ack_count_(0), |
| @@ -173,7 +174,9 @@ TracingControllerImpl::TracingControllerImpl() : |
| is_system_tracing_(false), |
| #endif |
| is_recording_(TraceLog::GetInstance()->IsEnabled()), |
| - is_monitoring_(false) { |
| + is_monitoring_(false), |
| + trace_data_sink_(NULL), |
| + monitoring_data_sink_(NULL) { |
| } |
| TracingControllerImpl::~TracingControllerImpl() { |
| @@ -199,7 +202,7 @@ bool TracingControllerImpl::GetCategories( |
| return false; |
| } |
| - bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback()); |
| + bool ok = DisableRecording(NULL); |
| DCHECK(ok); |
| return true; |
| } |
| @@ -285,9 +288,7 @@ void TracingControllerImpl::OnEnableRecordingDone( |
| callback.Run(); |
| } |
| -bool TracingControllerImpl::DisableRecording( |
| - const base::FilePath& result_file_path, |
| - const TracingFileResultCallback& callback) { |
| +bool TracingControllerImpl::DisableRecording(TraceDataSink* trace_data_sink) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (!can_disable_recording()) |
| @@ -298,8 +299,7 @@ bool TracingControllerImpl::DisableRecording( |
| // interfering with the process. |
| base::Closure on_disable_recording_done_callback = |
| base::Bind(&TracingControllerImpl::OnDisableRecordingDone, |
| - base::Unretained(this), |
| - result_file_path, callback); |
| + base::Unretained(this), trace_data_sink); |
| BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| base::Bind(&TracingControllerImpl::SetDisabledOnFileThread, |
| base::Unretained(this), |
| @@ -308,19 +308,15 @@ bool TracingControllerImpl::DisableRecording( |
| } |
| void TracingControllerImpl::OnDisableRecordingDone( |
| - const base::FilePath& result_file_path, |
| - const TracingFileResultCallback& callback) { |
| + TraceDataSink* trace_data_sink) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - pending_disable_recording_done_callback_ = callback; |
| - |
| #if defined(OS_ANDROID) |
| if (pending_get_categories_done_callback_.is_null()) |
| TraceLog::GetInstance()->AddClockSyncMetadataEvent(); |
| #endif |
| - if (!callback.is_null() || !result_file_path.empty()) |
| - result_file_.reset(new ResultFile(result_file_path)); |
| + trace_data_sink_ = trace_data_sink; |
| // Count myself (local trace) in pending_disable_recording_ack_count_, |
| // acked below. |
| @@ -442,7 +438,6 @@ void TracingControllerImpl::OnDisableMonitoringDone( |
| it != trace_message_filters_.end(); ++it) { |
| it->get()->SendDisableMonitoring(); |
| } |
| - |
| if (!callback.is_null()) |
| callback.Run(); |
| } |
| @@ -457,18 +452,16 @@ void TracingControllerImpl::GetMonitoringStatus( |
| } |
| bool TracingControllerImpl::CaptureMonitoringSnapshot( |
| - const base::FilePath& result_file_path, |
| - const TracingFileResultCallback& callback) { |
| + TraceDataSink* monitoring_data_sink) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (!can_disable_monitoring()) |
| return false; |
| - if (callback.is_null() && result_file_path.empty()) |
| + if (!monitoring_data_sink) |
| return false; |
| - pending_capture_monitoring_snapshot_done_callback_ = callback; |
| - monitoring_snapshot_file_.reset(new ResultFile(result_file_path)); |
| + monitoring_data_sink_ = monitoring_data_sink; |
| // Count myself in pending_capture_monitoring_snapshot_ack_count_, |
| // acked below. |
| @@ -685,10 +678,6 @@ void TracingControllerImpl::OnDisableRecordingAcked( |
| if (pending_disable_recording_ack_count_ != 0) |
| return; |
| - OnDisableRecordingComplete(); |
| -} |
| - |
| -void TracingControllerImpl::OnDisableRecordingComplete() { |
| // All acks (including from the subprocesses and the local trace) have been |
| // received. |
| is_recording_ = false; |
| @@ -697,34 +686,28 @@ void TracingControllerImpl::OnDisableRecordingComplete() { |
| if (!pending_get_categories_done_callback_.is_null()) { |
| pending_get_categories_done_callback_.Run(known_category_groups_); |
| pending_get_categories_done_callback_.Reset(); |
| - } else if (result_file_) { |
| - result_file_->Close( |
| - base::Bind(&TracingControllerImpl::OnResultFileClosed, |
| - base::Unretained(this))); |
| + } else if (trace_data_sink_) { |
| + trace_data_sink_->Close(); |
| + trace_data_sink_ = 0; |
| } |
| } |
| -void TracingControllerImpl::OnResultFileClosed() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - |
| - if (!result_file_) |
| - return; |
| - |
| - if (!pending_disable_recording_done_callback_.is_null()) { |
| - pending_disable_recording_done_callback_.Run(result_file_->path()); |
| - pending_disable_recording_done_callback_.Reset(); |
| - } |
| - result_file_.reset(); |
| -} |
| - |
| #if defined(OS_CHROMEOS) || defined(OS_WIN) |
| void TracingControllerImpl::OnEndSystemTracingAcked( |
| const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - if (result_file_) |
| - result_file_->WriteSystemTrace(events_str_ptr); |
| - |
| + if (trace_data_sink_) { |
| +#if defined(OS_WIN) |
| + // The Windows kernel events are kept into a JSon format stored as string |
| + // and must not be escaped. |
| + std::string json_string = events_str_ptr_->data(); |
| +#else |
| + std::string json_string = |
| + base::GetQuotedJSONString(events_str_ptr_->data()); |
| +#endif |
| + trace_data_sink_->SetSystemTrace(json_string); |
| + } |
| DCHECK(!is_system_tracing_); |
| std::vector<std::string> category_groups; |
| OnDisableRecordingAcked(NULL, category_groups); |
| @@ -763,25 +746,10 @@ void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked( |
| if (pending_capture_monitoring_snapshot_ack_count_ != 0) |
| return; |
| - if (monitoring_snapshot_file_) { |
| - monitoring_snapshot_file_->Close( |
| - base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed, |
| - base::Unretained(this))); |
| - } |
| -} |
| - |
| -void TracingControllerImpl::OnMonitoringSnapshotFileClosed() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - |
| - if (!monitoring_snapshot_file_) |
| - return; |
| - |
| - if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) { |
| - pending_capture_monitoring_snapshot_done_callback_.Run( |
| - monitoring_snapshot_file_->path()); |
| - pending_capture_monitoring_snapshot_done_callback_.Reset(); |
| + if (monitoring_data_sink_) { |
| + monitoring_data_sink_->Close(); |
| + monitoring_data_sink_ = NULL; |
| } |
| - monitoring_snapshot_file_.reset(); |
| } |
| void TracingControllerImpl::OnTraceDataCollected( |
| @@ -795,8 +763,8 @@ void TracingControllerImpl::OnTraceDataCollected( |
| return; |
| } |
| - if (result_file_) |
| - result_file_->Write(events_str_ptr); |
| + if (trace_data_sink_) |
| + trace_data_sink_->AddTraceChunk(events_str_ptr->data()); |
| } |
| void TracingControllerImpl::OnMonitoringTraceDataCollected( |
| @@ -808,8 +776,8 @@ void TracingControllerImpl::OnMonitoringTraceDataCollected( |
| return; |
| } |
| - if (monitoring_snapshot_file_) |
| - monitoring_snapshot_file_->Write(events_str_ptr); |
| + if (monitoring_data_sink_) |
| + monitoring_data_sink_->AddTraceChunk(events_str_ptr->data()); |
| } |
| void TracingControllerImpl::OnLocalTraceDataCollected( |