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"
7 #include "base/files/file_util.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "third_party/zlib/zlib.h"
15 class StringTraceDataEndpoint
: public TracingController::TraceDataEndpoint
{
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
));
32 ~StringTraceDataEndpoint() override
{}
34 CompletionCallback completion_callback_
;
36 DISALLOW_COPY_AND_ASSIGN(StringTraceDataEndpoint
);
39 class FileTraceDataEndpoint
: public TracingController::TraceDataEndpoint
{
41 explicit FileTraceDataEndpoint(const base::FilePath
& trace_file_path
,
42 const base::Closure
& callback
)
43 : file_path_(trace_file_path
),
44 completion_callback_(callback
),
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,
57 void ReceiveTraceFinalContents(const std::string
& contents
) override
{
58 BrowserThread::PostTask(
59 BrowserThread::FILE, FROM_HERE
,
60 base::Bind(&FileTraceDataEndpoint::CloseOnFileThread
, this));
64 ~FileTraceDataEndpoint() override
{ DCHECK(file_
== NULL
); }
66 void ReceiveTraceChunkOnFileThread(
67 const scoped_refptr
<base::RefCountedString
> chunk
) {
68 if (!OpenFileIfNeededOnFileThread())
71 fwrite(chunk
->data().c_str(), chunk
->data().size(), 1, file_
));
74 bool OpenFileIfNeededOnFileThread() {
77 file_
= base::OpenFile(file_path_
, "w");
79 LOG(ERROR
) << "Failed to open " << file_path_
.value();
85 void CloseOnFileThread() {
86 if (OpenFileIfNeededOnFileThread()) {
87 base::CloseFile(file_
);
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_
;
101 DISALLOW_COPY_AND_ASSIGN(FileTraceDataEndpoint
);
104 class StringTraceDataSink
: public TracingController::TraceDataSink
{
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
;
113 trace_string
= "{\"traceEvents\":[";
116 trace_string
+= chunk
;
118 AddTraceChunkAndPassToEndpoint(trace_string
);
121 void AddTraceChunkAndPassToEndpoint(const std::string
& 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
{
135 void Close() override
{
136 AddTraceChunkAndPassToEndpoint("]");
137 if (!system_trace_
.empty())
138 AddTraceChunkAndPassToEndpoint(",\"systemTraceEvents\": " +
140 if (!metadata_
.empty())
141 AddTraceChunkAndPassToEndpoint(",\"metadata\": " + metadata_
);
142 AddTraceChunkAndPassToEndpoint("}");
144 endpoint_
->ReceiveTraceFinalContents(trace_
);
148 ~StringTraceDataSink() override
{}
150 scoped_refptr
<TracingController::TraceDataEndpoint
> endpoint_
;
152 std::string system_trace_
;
153 std::string metadata_
;
155 DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink
);
158 class CompressedStringTraceDataSink
: public TracingController::TraceDataSink
{
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
,
174 void SetSystemTrace(const std::string
& data
) override
{
175 system_trace_
= data
;
178 void SetMetadata(const std::string
& data
) override
{
182 void Close() override
{
183 BrowserThread::PostTask(
184 BrowserThread::FILE, FROM_HERE
,
185 base::Bind(&CompressedStringTraceDataSink::CloseOnFileThread
, this));
189 ~CompressedStringTraceDataSink() override
{}
191 bool OpenZStreamOnFileThread() {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
196 if (already_tried_open_
)
199 already_tried_open_
= true;
200 stream_
.reset(new z_stream
);
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.
209 8, // memLevel = 8 is default.
214 void AddTraceChunkOnFileThread(
215 const scoped_refptr
<base::RefCountedString
> chunk_ptr
) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
218 if (compressed_trace_data_
.empty())
219 trace
= "{\"traceEvents\":[";
222 trace
+= chunk_ptr
->data();
223 AddTraceChunkAndCompressOnFileThread(trace
, false);
226 void AddTraceChunkAndCompressOnFileThread(const std::string
& chunk
,
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
229 if (!OpenZStreamOnFileThread())
232 const int kChunkSize
= 0x4000;
234 char buffer
[kChunkSize
];
236 stream_
->avail_in
= chunk
.size();
237 stream_
->next_in
= (unsigned char*)chunk
.data();
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
)) {
247 int bytes
= kChunkSize
- stream_
->avail_out
;
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())
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_
,
273 AddTraceChunkAndCompressOnFileThread("}", true);
275 deflateEnd(stream_
.get());
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
);
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