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