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 SetPowerTrace(const std::string
& data
) override
{ power_trace_
= data
; }
137 void Close() override
{
138 AddTraceChunkAndPassToEndpoint("]");
139 if (!system_trace_
.empty())
140 AddTraceChunkAndPassToEndpoint(",\"systemTraceEvents\": " +
142 if (!metadata_
.empty())
143 AddTraceChunkAndPassToEndpoint(",\"metadata\": " + metadata_
);
144 if (!power_trace_
.empty()) {
145 AddTraceChunkAndPassToEndpoint(",\"powerTraceAsString\": " +
149 AddTraceChunkAndPassToEndpoint("}");
151 endpoint_
->ReceiveTraceFinalContents(trace_
);
155 ~StringTraceDataSink() override
{}
157 scoped_refptr
<TracingController::TraceDataEndpoint
> endpoint_
;
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
{
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
,
182 void SetSystemTrace(const std::string
& data
) override
{
183 system_trace_
= data
;
186 void SetMetadata(const std::string
& data
) override
{
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));
199 ~CompressedStringTraceDataSink() override
{}
201 bool OpenZStreamOnFileThread() {
202 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
206 if (already_tried_open_
)
209 already_tried_open_
= true;
210 stream_
.reset(new z_stream
);
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.
219 8, // memLevel = 8 is default.
224 void AddTraceChunkOnFileThread(
225 const scoped_refptr
<base::RefCountedString
> chunk_ptr
) {
226 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
228 if (compressed_trace_data_
.empty())
229 trace
= "{\"traceEvents\":[";
232 trace
+= chunk_ptr
->data();
233 AddTraceChunkAndCompressOnFileThread(trace
, false);
236 void AddTraceChunkAndCompressOnFileThread(const std::string
& chunk
,
238 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
239 if (!OpenZStreamOnFileThread())
242 const int kChunkSize
= 0x4000;
244 char buffer
[kChunkSize
];
246 stream_
->avail_in
= chunk
.size();
247 stream_
->next_in
= (unsigned char*)chunk
.data();
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
)) {
257 int bytes
= kChunkSize
- stream_
->avail_out
;
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())
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_
,
283 if (!power_trace_
.empty()) {
284 AddTraceChunkAndCompressOnFileThread(
285 ",\"powerTraceAsString\": " + power_trace_
, false);
287 AddTraceChunkAndCompressOnFileThread("}", true);
289 deflateEnd(stream_
.get());
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
);
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