[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / tracing / tracing_controller_impl_data_sinks.cc
blob38fdfbcd34c02a214f715d5a759d441863e828a9
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 SetPowerTrace(const std::string& data) override { power_trace_ = data; }
137 void Close() override {
138 AddTraceChunkAndPassToEndpoint("]");
139 if (!system_trace_.empty())
140 AddTraceChunkAndPassToEndpoint(",\"systemTraceEvents\": " +
141 system_trace_);
142 if (!metadata_.empty())
143 AddTraceChunkAndPassToEndpoint(",\"metadata\": " + metadata_);
144 if (!power_trace_.empty()) {
145 AddTraceChunkAndPassToEndpoint(",\"powerTraceAsString\": " +
146 power_trace_);
149 AddTraceChunkAndPassToEndpoint("}");
151 endpoint_->ReceiveTraceFinalContents(trace_);
154 private:
155 ~StringTraceDataSink() override {}
157 scoped_refptr<TracingController::TraceDataEndpoint> endpoint_;
158 std::string trace_;
159 std::string system_trace_;
160 std::string metadata_;
161 std::string power_trace_;
163 DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
166 class CompressedStringTraceDataSink : public TracingController::TraceDataSink {
167 public:
168 explicit CompressedStringTraceDataSink(
169 scoped_refptr<TracingController::TraceDataEndpoint> endpoint)
170 : endpoint_(endpoint), already_tried_open_(false) {}
172 void AddTraceChunk(const std::string& chunk) override {
173 std::string tmp = chunk;
174 scoped_refptr<base::RefCountedString> chunk_ptr =
175 base::RefCountedString::TakeString(&tmp);
176 BrowserThread::PostTask(
177 BrowserThread::FILE, FROM_HERE,
178 base::Bind(&CompressedStringTraceDataSink::AddTraceChunkOnFileThread,
179 this, chunk_ptr));
182 void SetSystemTrace(const std::string& data) override {
183 system_trace_ = data;
186 void SetMetadata(const std::string& data) override {
187 metadata_ = data;
190 void SetPowerTrace(const std::string& data) override { power_trace_ = data; }
192 void Close() override {
193 BrowserThread::PostTask(
194 BrowserThread::FILE, FROM_HERE,
195 base::Bind(&CompressedStringTraceDataSink::CloseOnFileThread, this));
198 private:
199 ~CompressedStringTraceDataSink() override {}
201 bool OpenZStreamOnFileThread() {
202 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
203 if (stream_)
204 return true;
206 if (already_tried_open_)
207 return false;
209 already_tried_open_ = true;
210 stream_.reset(new z_stream);
211 *stream_ = {0};
212 stream_->zalloc = Z_NULL;
213 stream_->zfree = Z_NULL;
214 stream_->opaque = Z_NULL;
216 int result = deflateInit2(stream_.get(), Z_DEFAULT_COMPRESSION, Z_DEFLATED,
217 // 16 is added to produce a gzip header + trailer.
218 MAX_WBITS + 16,
219 8, // memLevel = 8 is default.
220 Z_DEFAULT_STRATEGY);
221 return result == 0;
224 void AddTraceChunkOnFileThread(
225 const scoped_refptr<base::RefCountedString> chunk_ptr) {
226 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
227 std::string trace;
228 if (compressed_trace_data_.empty())
229 trace = "{\"traceEvents\":[";
230 else
231 trace = ",";
232 trace += chunk_ptr->data();
233 AddTraceChunkAndCompressOnFileThread(trace, false);
236 void AddTraceChunkAndCompressOnFileThread(const std::string& chunk,
237 bool finished) {
238 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
239 if (!OpenZStreamOnFileThread())
240 return;
242 const int kChunkSize = 0x4000;
244 char buffer[kChunkSize];
245 int err;
246 stream_->avail_in = chunk.size();
247 stream_->next_in = (unsigned char*)chunk.data();
248 do {
249 stream_->avail_out = kChunkSize;
250 stream_->next_out = (unsigned char*)buffer;
251 err = deflate(stream_.get(), finished ? Z_FINISH : Z_NO_FLUSH);
252 if (err != Z_OK && (err != Z_STREAM_END && finished)) {
253 stream_.reset();
254 return;
257 int bytes = kChunkSize - stream_->avail_out;
258 if (bytes) {
259 std::string compressed_chunk = std::string(buffer, bytes);
260 compressed_trace_data_ += compressed_chunk;
261 endpoint_->ReceiveTraceChunk(compressed_chunk);
263 } while (stream_->avail_out == 0);
266 void CloseOnFileThread() {
267 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
268 if (!OpenZStreamOnFileThread())
269 return;
271 if (compressed_trace_data_.empty())
272 AddTraceChunkAndCompressOnFileThread("{\"traceEvents\":[", false);
274 AddTraceChunkAndCompressOnFileThread("]", false);
275 if (!system_trace_.empty()) {
276 AddTraceChunkAndCompressOnFileThread(
277 ",\"systemTraceEvents\": " + system_trace_, false);
279 if (!metadata_.empty()) {
280 AddTraceChunkAndCompressOnFileThread(",\"metadata\": " + metadata_,
281 false);
283 if (!power_trace_.empty()) {
284 AddTraceChunkAndCompressOnFileThread(
285 ",\"powerTraceAsString\": " + power_trace_, false);
287 AddTraceChunkAndCompressOnFileThread("}", true);
289 deflateEnd(stream_.get());
290 stream_.reset();
292 endpoint_->ReceiveTraceFinalContents(compressed_trace_data_);
295 scoped_refptr<TracingController::TraceDataEndpoint> endpoint_;
296 scoped_ptr<z_stream> stream_;
297 bool already_tried_open_;
298 std::string compressed_trace_data_;
299 std::string system_trace_;
300 std::string metadata_;
301 std::string power_trace_;
303 DISALLOW_COPY_AND_ASSIGN(CompressedStringTraceDataSink);
306 } // namespace
308 scoped_refptr<TracingController::TraceDataSink>
309 TracingController::CreateStringSink(
310 const base::Callback<void(base::RefCountedString*)>& callback) {
311 return new StringTraceDataSink(new StringTraceDataEndpoint(callback));
314 scoped_refptr<TracingController::TraceDataSink>
315 TracingController::CreateCompressedStringSink(
316 scoped_refptr<TracingController::TraceDataEndpoint> endpoint) {
317 return new CompressedStringTraceDataSink(endpoint);
320 scoped_refptr<TracingController::TraceDataSink>
321 TracingController::CreateFileSink(const base::FilePath& file_path,
322 const base::Closure& callback) {
323 return new StringTraceDataSink(
324 CreateFileEndpoint(file_path, callback));
327 scoped_refptr<TracingController::TraceDataEndpoint>
328 TracingController::CreateCallbackEndpoint(
329 const base::Callback<void(base::RefCountedString*)>& callback) {
330 return new StringTraceDataEndpoint(callback);
333 scoped_refptr<TracingController::TraceDataEndpoint>
334 TracingController::CreateFileEndpoint(const base::FilePath& file_path,
335 const base::Closure& callback) {
336 return new FileTraceDataEndpoint(file_path, callback);
339 } // namespace content