Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / tracing / tracing_controller_impl.cc
index 5fe4d2f..3e8e1ac 100644 (file)
@@ -5,8 +5,9 @@
 
 #include "base/bind.h"
 #include "base/debug/trace_event.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
 #include "base/json/string_escape.h"
+#include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "content/browser/tracing/trace_message_filter.h"
 #include "content/browser/tracing/tracing_ui.h"
@@ -34,134 +35,133 @@ 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) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-        base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
-                   base::Unretained(this), 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) {}
+
+  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(
+            &FileTraceDataSink::AddTraceChunkOnFileThread, this, chunk_ptr));
   }
-  void Close(const base::Closure& callback) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-        base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
-                   base::Unretained(this), callback));
+  void SetSystemTrace(const std::string& data) override {
+    system_trace_ = data;
   }
-  void WriteSystemTrace(
-      const scoped_refptr<base::RefCountedString>& events_str_ptr) {
+  void Close() override {
     BrowserThread::PostTask(
         BrowserThread::FILE,
         FROM_HERE,
-        base::Bind(&TracingControllerImpl::ResultFile::WriteSystemTraceTask,
-                   base::Unretained(this), events_str_ptr));
+        base::Bind(&FileTraceDataSink::CloseOnFileThread, 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);
+  ~FileTraceDataSink() override { DCHECK(file_ == NULL); }
+
+  void AddTraceChunkOnFileThread(
+      const scoped_refptr<base::RefCountedString> chunk) {
+    if (file_ != NULL)
+      fputc(',', file_);
+    else if (!OpenFileIfNeededOnFileThread())
+      return;
+    ignore_result(fwrite(chunk->data().c_str(), strlen(chunk->data().c_str()),
+        1, file_));
+  }
+
+  bool OpenFileIfNeededOnFileThread() {
+    if (file_ != NULL)
+      return true;
+    file_ = base::OpenFile(file_path_, "w");
+    if (file_ == NULL) {
+      LOG(ERROR) << "Failed to open " << file_path_.value();
+      return false;
+    }
+    const char preamble[] = "{\"traceEvents\": [";
+    ignore_result(fwrite(preamble, strlen(preamble), 1, file_));
+    return true;
+  }
+
+  void CloseOnFileThread() {
+    if (OpenFileIfNeededOnFileThread()) {
+      fputc(']', file_);
+      if (!system_trace_.empty()) {
+        const char systemTraceEvents[] = ",\"systemTraceEvents\": ";
+        ignore_result(fwrite(systemTraceEvents, strlen(systemTraceEvents),
+            1, file_));
+        ignore_result(fwrite(system_trace_.c_str(),
+            strlen(system_trace_.c_str()), 1, file_));
+      }
+      fputc('}', file_);
+      base::CloseFile(file_);
+      file_ = NULL;
+    }
+    BrowserThread::PostTask(
+        BrowserThread::UI,
+        FROM_HERE,
+        base::Bind(&FileTraceDataSink::FinalizeOnUIThread, this));
+  }
+
+  void FinalizeOnUIThread() { completion_callback_.Run(); }
 
+  base::FilePath file_path_;
+  base::Closure completion_callback_;
   FILE* file_;
-  base::FilePath path_;
-  bool has_at_least_one_result_;
-  scoped_refptr<base::RefCountedString> system_trace_;
+  std::string system_trace_;
 
-  DISALLOW_COPY_AND_ASSIGN(ResultFile);
+  DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink);
 };
 
-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)));
-}
-
-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;
-  }
-  const char* preamble = "{\"traceEvents\": [";
-  size_t written = fwrite(preamble, strlen(preamble), 1, file_);
-  DCHECK(written == 1);
-}
+class StringTraceDataSink : public TracingController::TraceDataSink {
+ public:
+  typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
 
-void TracingControllerImpl::ResultFile::WriteTask(
-    const scoped_refptr<base::RefCountedString>& events_str_ptr) {
-  if (!file_ || !events_str_ptr->data().size())
-    return;
+  explicit StringTraceDataSink(CompletionCallback callback)
+      : completion_callback_(callback) {}
 
-  // 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
+  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);
+  void SetSystemTrace(const std::string& data) override {
+    system_trace_ = data;
+  }
+  void Close() override {
+    std::string result = "{\"traceEvents\":[" + trace_ + "]";
+    if (!system_trace_.empty())
+      result += ",\"systemTraceEvents\": " + system_trace_;
+    result += "}";
 
-  if (system_trace_) {
-#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
+    scoped_refptr<base::RefCountedString> str =
+        base::RefCountedString::TakeString(&result);
+    completion_callback_.Run(str.get());
+  }
 
-    const char* systemTraceHead = ",\n\"systemTraceEvents\": ";
-    written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_);
-    DCHECK(written == 1);
+ private:
+  ~StringTraceDataSink() override {}
 
-    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;
-  }
+  DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
+};
 
-  const char* trailout = "}";
-  written = fwrite(trailout, strlen(trailout), 1, file_);
-  DCHECK(written == 1);
-  base::CloseFile(file_);
-  file_ = NULL;
+}  // namespace
 
-  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
+TracingController* TracingController::GetInstance() {
+  return TracingControllerImpl::GetInstance();
 }
 
-
 TracingControllerImpl::TracingControllerImpl() :
     pending_disable_recording_ack_count_(0),
     pending_capture_monitoring_snapshot_ack_count_(0),
@@ -199,7 +199,7 @@ bool TracingControllerImpl::GetCategories(
     return false;
   }
 
-  bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback());
+  bool ok = DisableRecording(NULL);
   DCHECK(ok);
   return true;
 }
@@ -286,20 +286,18 @@ void TracingControllerImpl::OnEnableRecordingDone(
 }
 
 bool TracingControllerImpl::DisableRecording(
-    const base::FilePath& result_file_path,
-    const TracingFileResultCallback& callback) {
+    const scoped_refptr<TraceDataSink>& trace_data_sink) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   if (!can_disable_recording())
     return false;
 
+  trace_data_sink_ = trace_data_sink;
   trace_options_ = TraceOptions();
   // Disable local trace early to avoid traces during end-tracing process from
   // interfering with the process.
-  base::Closure on_disable_recording_done_callback =
-      base::Bind(&TracingControllerImpl::OnDisableRecordingDone,
-                 base::Unretained(this),
-                 result_file_path, callback);
+  base::Closure on_disable_recording_done_callback = base::Bind(
+      &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
       base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
                  base::Unretained(this),
@@ -307,21 +305,14 @@ bool TracingControllerImpl::DisableRecording(
   return true;
 }
 
-void TracingControllerImpl::OnDisableRecordingDone(
-    const base::FilePath& result_file_path,
-    const TracingFileResultCallback& callback) {
+void TracingControllerImpl::OnDisableRecordingDone() {
   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));
-
   // Count myself (local trace) in pending_disable_recording_ack_count_,
   // acked below.
   pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
@@ -431,6 +422,18 @@ bool TracingControllerImpl::DisableMonitoring(
   return true;
 }
 
+scoped_refptr<TracingController::TraceDataSink>
+TracingController::CreateStringSink(
+    const base::Callback<void(base::RefCountedString*)>& callback) {
+  return new StringTraceDataSink(callback);
+}
+
+scoped_refptr<TracingController::TraceDataSink>
+TracingController::CreateFileSink(const base::FilePath& file_path,
+                                  const base::Closure& callback) {
+  return new FileTraceDataSink(file_path, callback);
+}
+
 void TracingControllerImpl::OnDisableMonitoringDone(
     const DisableMonitoringDoneCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -442,7 +445,6 @@ void TracingControllerImpl::OnDisableMonitoringDone(
       it != trace_message_filters_.end(); ++it) {
     it->get()->SendDisableMonitoring();
   }
-
   if (!callback.is_null())
     callback.Run();
 }
@@ -457,18 +459,16 @@ void TracingControllerImpl::GetMonitoringStatus(
 }
 
 bool TracingControllerImpl::CaptureMonitoringSnapshot(
-    const base::FilePath& result_file_path,
-    const TracingFileResultCallback& callback) {
+    const scoped_refptr<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.get())
     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 +685,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,24 +693,10 @@ 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)));
-  }
-}
-
-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();
+  } else if (trace_data_sink_.get()) {
+    trace_data_sink_->Close();
+    trace_data_sink_ = NULL;
   }
-  result_file_.reset();
 }
 
 #if defined(OS_CHROMEOS) || defined(OS_WIN)
@@ -722,9 +704,17 @@ 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_.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 = 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 +753,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_.get()) {
+    monitoring_data_sink_->Close();
+    monitoring_data_sink_ = NULL;
   }
-  monitoring_snapshot_file_.reset();
 }
 
 void TracingControllerImpl::OnTraceDataCollected(
@@ -795,8 +770,8 @@ void TracingControllerImpl::OnTraceDataCollected(
     return;
   }
 
-  if (result_file_)
-    result_file_->Write(events_str_ptr);
+  if (trace_data_sink_.get())
+    trace_data_sink_->AddTraceChunk(events_str_ptr->data());
 }
 
 void TracingControllerImpl::OnMonitoringTraceDataCollected(
@@ -808,8 +783,8 @@ void TracingControllerImpl::OnMonitoringTraceDataCollected(
     return;
   }
 
-  if (monitoring_snapshot_file_)
-    monitoring_snapshot_file_->Write(events_str_ptr);
+  if (monitoring_data_sink_.get())
+    monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
 }
 
 void TracingControllerImpl::OnLocalTraceDataCollected(