Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / devtools / devtools_tracing_handler.cc
1 // Copyright (c) 2012 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/devtools/devtools_tracing_handler.h"
6
7 #include <cmath>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/file_util.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted_memory.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/time/time.h"
19 #include "base/timer/timer.h"
20 #include "base/values.h"
21 #include "content/browser/devtools/devtools_http_handler_impl.h"
22 #include "content/browser/devtools/devtools_protocol_constants.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/tracing_controller.h"
25
26 namespace content {
27
28 namespace {
29
30 const char kRecordUntilFull[]   = "record-until-full";
31 const char kRecordContinuously[] = "record-continuously";
32 const char kEnableSampling[] = "enable-sampling";
33
34 void ReadFile(
35     const base::FilePath& path,
36     const base::Callback<void(const scoped_refptr<base::RefCountedString>&)>
37         callback) {
38   std::string trace_data;
39   if (!base::ReadFileToString(path, &trace_data))
40     LOG(ERROR) << "Failed to read file: " << path.value();
41   base::DeleteFile(path, false);
42   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
43       base::Bind(callback, make_scoped_refptr(
44           base::RefCountedString::TakeString(&trace_data))));
45 }
46
47 }  // namespace
48
49 DevToolsTracingHandler::DevToolsTracingHandler()
50     : weak_factory_(this) {
51   RegisterCommandHandler(devtools::Tracing::start::kName,
52                          base::Bind(&DevToolsTracingHandler::OnStart,
53                                     base::Unretained(this)));
54   RegisterCommandHandler(devtools::Tracing::end::kName,
55                          base::Bind(&DevToolsTracingHandler::OnEnd,
56                                     base::Unretained(this)));
57 }
58
59 DevToolsTracingHandler::~DevToolsTracingHandler() {
60 }
61
62 void DevToolsTracingHandler::BeginReadingRecordingResult(
63     const base::FilePath& path) {
64   BrowserThread::PostTask(
65       BrowserThread::FILE, FROM_HERE,
66       base::Bind(&ReadFile, path,
67                  base::Bind(&DevToolsTracingHandler::ReadRecordingResult,
68                             weak_factory_.GetWeakPtr())));
69 }
70
71 void DevToolsTracingHandler::ReadRecordingResult(
72     const scoped_refptr<base::RefCountedString>& trace_data) {
73   if (trace_data->data().size()) {
74     scoped_ptr<base::Value> trace_value(base::JSONReader::Read(
75         trace_data->data()));
76     base::DictionaryValue* dictionary = NULL;
77     bool ok = trace_value->GetAsDictionary(&dictionary);
78     DCHECK(ok);
79     base::ListValue* list = NULL;
80     ok = dictionary->GetList("traceEvents", &list);
81     DCHECK(ok);
82     std::string buffer;
83     for (size_t i = 0; i < list->GetSize(); ++i) {
84       std::string item;
85       base::Value* item_value;
86       list->Get(i, &item_value);
87       base::JSONWriter::Write(item_value, &item);
88       if (buffer.size())
89         buffer.append(",");
90       buffer.append(item);
91       if (i % 1000 == 0) {
92         OnTraceDataCollected(buffer);
93         buffer.clear();
94       }
95     }
96     if (buffer.size())
97       OnTraceDataCollected(buffer);
98   }
99
100   SendNotification(devtools::Tracing::tracingComplete::kName, NULL);
101 }
102
103 void DevToolsTracingHandler::OnTraceDataCollected(
104     const std::string& trace_fragment) {
105   // Hand-craft protocol notification message so we can substitute JSON
106   // that we already got as string as a bare object, not a quoted string.
107   std::string message = base::StringPrintf(
108       "{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }",
109       devtools::Tracing::dataCollected::kName,
110       devtools::Tracing::dataCollected::kParamValue,
111       trace_fragment.c_str());
112   SendRawMessage(message);
113 }
114
115 TracingController::Options DevToolsTracingHandler::TraceOptionsFromString(
116     const std::string& options) {
117   std::vector<std::string> split;
118   std::vector<std::string>::iterator iter;
119   int ret = 0;
120
121   base::SplitString(options, ',', &split);
122   for (iter = split.begin(); iter != split.end(); ++iter) {
123     if (*iter == kRecordUntilFull) {
124       ret &= ~TracingController::RECORD_CONTINUOUSLY;
125     } else if (*iter == kRecordContinuously) {
126       ret |= TracingController::RECORD_CONTINUOUSLY;
127     } else if (*iter == kEnableSampling) {
128       ret |= TracingController::ENABLE_SAMPLING;
129     }
130   }
131   return static_cast<TracingController::Options>(ret);
132 }
133
134 scoped_refptr<DevToolsProtocol::Response>
135 DevToolsTracingHandler::OnStart(
136     scoped_refptr<DevToolsProtocol::Command> command) {
137   std::string categories;
138   base::DictionaryValue* params = command->params();
139   if (params)
140     params->GetString(devtools::Tracing::start::kParamCategories, &categories);
141
142   TracingController::Options options = TracingController::DEFAULT_OPTIONS;
143   if (params && params->HasKey(devtools::Tracing::start::kParamOptions)) {
144     std::string options_param;
145     params->GetString(devtools::Tracing::start::kParamOptions, &options_param);
146     options = TraceOptionsFromString(options_param);
147   }
148
149   if (params && params->HasKey(
150       devtools::Tracing::start::kParamBufferUsageReportingInterval)) {
151     double usage_reporting_interval = 0.0;
152     params->GetDouble(
153         devtools::Tracing::start::kParamBufferUsageReportingInterval,
154         &usage_reporting_interval);
155     if (usage_reporting_interval > 0) {
156       base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
157           std::ceil(usage_reporting_interval));
158       buffer_usage_poll_timer_.reset(new base::Timer(
159           FROM_HERE,
160           interval,
161           base::Bind(
162               base::IgnoreResult(&TracingController::GetTraceBufferPercentFull),
163               base::Unretained(TracingController::GetInstance()),
164               base::Bind(&DevToolsTracingHandler::OnBufferUsage,
165                          weak_factory_.GetWeakPtr())),
166           true));
167       buffer_usage_poll_timer_->Reset();
168     }
169   }
170
171   TracingController::GetInstance()->EnableRecording(
172       categories, options, TracingController::EnableRecordingDoneCallback());
173
174   return NULL;
175 }
176
177 void DevToolsTracingHandler::OnBufferUsage(float usage) {
178   base::DictionaryValue* params = new base::DictionaryValue();
179   params->SetDouble(devtools::Tracing::bufferUsage::kParamValue, usage);
180   SendNotification(devtools::Tracing::bufferUsage::kName, params);
181 }
182
183 scoped_refptr<DevToolsProtocol::Response>
184 DevToolsTracingHandler::OnEnd(
185     scoped_refptr<DevToolsProtocol::Command> command) {
186   buffer_usage_poll_timer_.reset();
187   TracingController::GetInstance()->DisableRecording(
188       base::FilePath(),
189       base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
190                  weak_factory_.GetWeakPtr()));
191   return command->SuccessResponse(NULL);
192 }
193
194 }  // namespace content