Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / tracing / tracing_controller_impl_data_sinks.cc
blob2886cabf3147c0b96e46846f743e78cd99c7c655
1 // Copyright 2015 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 #include "content/browser/tracing/tracing_controller_impl.h"
6 #include "base/bind.h"
7 #include "base/files/file_util.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "third_party/zlib/zlib.h"
11 namespace content {
13 namespace {
15 class StringTraceDataEndpoint : public TracingController::TraceDataEndpoint {
16 public:
17 typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
19 explicit StringTraceDataEndpoint(CompletionCallback callback)
20 : completion_callback_(callback) {}
22 void ReceiveTraceFinalContents(const std::string& contents) override {
23 std::string tmp = contents;
24 scoped_refptr<base::RefCountedString> str =
25 base::RefCountedString::TakeString(&tmp);
27 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
28 base::Bind(completion_callback_, str));
31 private:
32 ~StringTraceDataEndpoint() override {}
34 CompletionCallback completion_callback_;
36 DISALLOW_COPY_AND_ASSIGN(StringTraceDataEndpoint);
39 class FileTraceDataEndpoint : public TracingController::TraceDataEndpoint {
40 public:
41 explicit FileTraceDataEndpoint(const base::FilePath& trace_file_path,
42 const base::Closure& callback)
43 : file_path_(trace_file_path),
44 completion_callback_(callback),
45 file_(NULL) {}
47 void ReceiveTraceChunk(const std::string& chunk) override {
48 std::string tmp = chunk;
49 scoped_refptr<base::RefCountedString> chunk_ptr =
50 base::RefCountedString::TakeString(&tmp);
51 BrowserThread::PostTask(
52 BrowserThread::FILE, FROM_HERE,
53 base::Bind(&FileTraceDataEndpoint::ReceiveTraceChunkOnFileThread, this,
54 chunk_ptr));
57 void ReceiveTraceFinalContents(const std::string& contents) override {
58 BrowserThread::PostTask(
59 BrowserThread::FILE, FROM_HERE,
60 base::Bind(&FileTraceDataEndpoint::CloseOnFileThread, this));
63 private:
64 ~FileTraceDataEndpoint() override { DCHECK(file_ == NULL); }
66 void ReceiveTraceChunkOnFileThread(
67 const scoped_refptr<base::RefCountedString> chunk) {
68 if (!OpenFileIfNeededOnFileThread())
69 return;
70 ignore_result(
71 fwrite(chunk->data().c_str(), chunk->data().size(), 1, file_));
74 bool OpenFileIfNeededOnFileThread() {
75 if (file_ != NULL)
76 return true;
77 file_ = base::OpenFile(file_path_, "w");
78 if (file_ == NULL) {
79 LOG(ERROR) << "Failed to open " << file_path_.value();
80 return false;
82 return true;
85 void CloseOnFileThread() {
86 if (OpenFileIfNeededOnFileThread()) {
87 base::CloseFile(file_);
88 file_ = NULL;
90 BrowserThread::PostTask(
91 BrowserThread::UI, FROM_HERE,
92 base::Bind(&FileTraceDataEndpoint::FinalizeOnUIThread, this));
95 void FinalizeOnUIThread() { completion_callback_.Run(); }
97 base::FilePath file_path_;
98 base::Closure completion_callback_;
99 FILE* file_;
101 DISALLOW_COPY_AND_ASSIGN(FileTraceDataEndpoint);
104 class StringTraceDataSink : public TracingController::TraceDataSink {
105 public:
106 explicit StringTraceDataSink(
107 scoped_refptr<TracingController::TraceDataEndpoint> endpoint)
108 : endpoint_(endpoint) {}
110 void AddTraceChunk(const std::string& chunk) override {
111 std::string trace_string;
112 if (trace_.empty())
113 trace_string = "{\"traceEvents\":[";
114 else
115 trace_string = ",";
116 trace_string += chunk;
118 AddTraceChunkAndPassToEndpoint(trace_string);
121 void AddTraceChunkAndPassToEndpoint(const std::string& chunk) {
122 trace_ += chunk;
124 endpoint_->ReceiveTraceChunk(chunk);
127 void SetSystemTrace(const std::string& data) override {
128 system_trace_ = data;
131 void SetMetadata(const std::string& data) override {
132 metadata_ = data;
135 void Close() override {
136 AddTraceChunkAndPassToEndpoint("]");
137 if (!system_trace_.empty())
138 AddTraceChunkAndPassToEndpoint(",\"systemTraceEvents\": " +
139 system_trace_);
140 if (!metadata_.empty())
141 AddTraceChunkAndPassToEndpoint(",\"metadata\": " + metadata_);
142 AddTraceChunkAndPassToEndpoint("}");
144 endpoint_->ReceiveTraceFinalContents(trace_);
147 private:
148 ~StringTraceDataSink() override {}
150 scoped_refptr<TracingController::TraceDataEndpoint> endpoint_;
151 std::string trace_;
152 std::string system_trace_;
153 std::string metadata_;
155 DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
158 class CompressedStringTraceDataSink : public TracingController::TraceDataSink {
159 public:
160 explicit CompressedStringTraceDataSink(
161 scoped_refptr<TracingController::TraceDataEndpoint> endpoint)
162 : endpoint_(endpoint), already_tried_open_(false) {}
164 void AddTraceChunk(const std::string& chunk) override {
165 std::string tmp = chunk;
166 scoped_refptr<base::RefCountedString> chunk_ptr =
167 base::RefCountedString::TakeString(&tmp);
168 BrowserThread::PostTask(
169 BrowserThread::FILE, FROM_HERE,
170 base::Bind(&CompressedStringTraceDataSink::AddTraceChunkOnFileThread,
171 this, chunk_ptr));
174 void SetSystemTrace(const std::string& data) override {
175 system_trace_ = data;
178 void SetMetadata(const std::string& data) override {
179 metadata_ = data;
182 void Close() override {
183 BrowserThread::PostTask(
184 BrowserThread::FILE, FROM_HERE,
185 base::Bind(&CompressedStringTraceDataSink::CloseOnFileThread, this));
188 private:
189 ~CompressedStringTraceDataSink() override {}
191 bool OpenZStreamOnFileThread() {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
193 if (stream_)
194 return true;
196 if (already_tried_open_)
197 return false;
199 already_tried_open_ = true;
200 stream_.reset(new z_stream);
201 *stream_ = {0};
202 stream_->zalloc = Z_NULL;
203 stream_->zfree = Z_NULL;
204 stream_->opaque = Z_NULL;
206 int result = deflateInit2(stream_.get(), Z_DEFAULT_COMPRESSION, Z_DEFLATED,
207 // 16 is added to produce a gzip header + trailer.
208 MAX_WBITS + 16,
209 8, // memLevel = 8 is default.
210 Z_DEFAULT_STRATEGY);
211 return result == 0;
214 void AddTraceChunkOnFileThread(
215 const scoped_refptr<base::RefCountedString> chunk_ptr) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
217 std::string trace;
218 if (compressed_trace_data_.empty())
219 trace = "{\"traceEvents\":[";
220 else
221 trace = ",";
222 trace += chunk_ptr->data();
223 AddTraceChunkAndCompressOnFileThread(trace, false);
226 void AddTraceChunkAndCompressOnFileThread(const std::string& chunk,
227 bool finished) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
229 if (!OpenZStreamOnFileThread())
230 return;
232 const int kChunkSize = 0x4000;
234 char buffer[kChunkSize];
235 int err;
236 stream_->avail_in = chunk.size();
237 stream_->next_in = (unsigned char*)chunk.data();
238 do {
239 stream_->avail_out = kChunkSize;
240 stream_->next_out = (unsigned char*)buffer;
241 err = deflate(stream_.get(), finished ? Z_FINISH : Z_NO_FLUSH);
242 if (err != Z_OK && (err != Z_STREAM_END && finished)) {
243 stream_.reset();
244 return;
247 int bytes = kChunkSize - stream_->avail_out;
248 if (bytes) {
249 std::string compressed_chunk = std::string(buffer, bytes);
250 compressed_trace_data_ += compressed_chunk;
251 endpoint_->ReceiveTraceChunk(compressed_chunk);
253 } while (stream_->avail_out == 0);
256 void CloseOnFileThread() {
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
258 if (!OpenZStreamOnFileThread())
259 return;
261 if (compressed_trace_data_.empty())
262 AddTraceChunkAndCompressOnFileThread("{\"traceEvents\":[", false);
264 AddTraceChunkAndCompressOnFileThread("]", false);
265 if (!system_trace_.empty()) {
266 AddTraceChunkAndCompressOnFileThread(
267 ",\"systemTraceEvents\": " + system_trace_, false);
269 if (!metadata_.empty()) {
270 AddTraceChunkAndCompressOnFileThread(",\"metadata\": " + metadata_,
271 false);
273 AddTraceChunkAndCompressOnFileThread("}", true);
275 deflateEnd(stream_.get());
276 stream_.reset();
278 endpoint_->ReceiveTraceFinalContents(compressed_trace_data_);
281 scoped_refptr<TracingController::TraceDataEndpoint> endpoint_;
282 scoped_ptr<z_stream> stream_;
283 bool already_tried_open_;
284 std::string compressed_trace_data_;
285 std::string system_trace_;
286 std::string metadata_;
288 DISALLOW_COPY_AND_ASSIGN(CompressedStringTraceDataSink);
291 } // namespace
293 scoped_refptr<TracingController::TraceDataSink>
294 TracingController::CreateStringSink(
295 const base::Callback<void(base::RefCountedString*)>& callback) {
296 return new StringTraceDataSink(new StringTraceDataEndpoint(callback));
299 scoped_refptr<TracingController::TraceDataSink>
300 TracingController::CreateCompressedStringSink(
301 scoped_refptr<TracingController::TraceDataEndpoint> endpoint) {
302 return new CompressedStringTraceDataSink(endpoint);
305 scoped_refptr<TracingController::TraceDataSink>
306 TracingController::CreateFileSink(const base::FilePath& file_path,
307 const base::Closure& callback) {
308 return new StringTraceDataSink(
309 CreateFileEndpoint(file_path, callback));
312 scoped_refptr<TracingController::TraceDataEndpoint>
313 TracingController::CreateCallbackEndpoint(
314 const base::Callback<void(base::RefCountedString*)>& callback) {
315 return new StringTraceDataEndpoint(callback);
318 scoped_refptr<TracingController::TraceDataEndpoint>
319 TracingController::CreateFileEndpoint(const base::FilePath& file_path,
320 const base::Closure& callback) {
321 return new FileTraceDataEndpoint(file_path, callback);
324 } // namespace content