Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / browser / tracing / trace_subscriber_stdio.cc
blob2c6aede56cef0738459828dda7b8d58b04daa925
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.
5 #include "content/browser/tracing/trace_subscriber_stdio.h"
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "content/public/browser/browser_thread.h"
14 namespace content {
16 // All method calls on this class are done on a SequencedWorkerPool thread.
17 class TraceSubscriberStdio::TraceSubscriberStdioWorker
18 : public base::RefCountedThreadSafe<TraceSubscriberStdioWorker> {
19 public:
20 TraceSubscriberStdioWorker(const base::FilePath& path,
21 FileType file_type,
22 bool has_system_trace)
23 : path_(path),
24 file_type_(file_type),
25 has_system_trace_(has_system_trace),
26 file_(0),
27 needs_comma_(false),
28 wrote_trace_(false),
29 has_pending_system_trace_(false),
30 wrote_system_trace_(false) {}
32 void OnTraceStart() {
33 DCHECK(!file_);
34 file_ = file_util::OpenFile(path_, "w+");
35 if (!IsValid()) {
36 LOG(ERROR) << "Failed to open performance trace file: " << path_.value();
37 return;
40 LOG(INFO) << "Logging performance trace to file: " << path_.value();
41 if (file_type_ == FILE_TYPE_PROPERTY_LIST)
42 WriteString("{\"traceEvents\":");
43 WriteString("[");
46 void OnTraceData(const scoped_refptr<base::RefCountedString>& data_ptr) {
47 if (!IsValid())
48 return;
49 DCHECK(!data_ptr->data().empty());
50 if (needs_comma_)
51 WriteString(",");
52 WriteString(data_ptr->data());
53 needs_comma_ = true;
56 void OnSystemTraceData(
57 const scoped_refptr<base::RefCountedString>& data_ptr) {
58 if (wrote_trace_) {
59 WriteSystemTrace(data_ptr);
60 End();
61 } else {
62 pending_system_trace_ = data_ptr;
63 has_pending_system_trace_ = true;
67 void OnTraceEnd() {
68 if (!IsValid())
69 return;
70 WriteString("]");
72 wrote_trace_ = true;
74 if (!has_system_trace_ || wrote_system_trace_) {
75 End();
76 return;
79 WriteString(",");
80 if (has_pending_system_trace_) {
81 WriteSystemTrace(pending_system_trace_);
82 End();
86 private:
87 friend class base::RefCountedThreadSafe<TraceSubscriberStdioWorker>;
89 ~TraceSubscriberStdioWorker() {
90 CloseFile();
93 bool IsValid() const {
94 return file_ && (0 == ferror(file_));
97 void CloseFile() {
98 if (file_) {
99 fclose(file_);
100 file_ = 0;
105 void End() {
106 if (file_type_ == FILE_TYPE_PROPERTY_LIST)
107 WriteString("}");
108 CloseFile();
111 void WriteSystemTrace(const scoped_refptr<base::RefCountedString>& data_ptr) {
112 // Newlines need to be replaced with the string "\n" to be parsed correctly.
113 // Double quotes need to be replaced with the string "\"".
114 // System logs are ASCII.
115 const std::string& data = data_ptr->data();
116 const char* chars = data.c_str();
117 WriteString("\"systemTraceEvents\":\"");
118 size_t old_index = 0;
119 for (size_t new_index = data.find_first_of("\n\"");
120 std::string::npos != new_index;
121 old_index = new_index + 1,
122 new_index = data.find_first_of("\n\"", old_index)) {
123 WriteChars(chars + old_index, new_index - old_index);
124 if (chars[new_index] == '\n')
125 WriteChars("\\n", 2);
126 else
127 WriteChars("\\\"", 2);
129 WriteChars(chars + old_index, data.size() - old_index);
130 WriteString("\"");
131 wrote_system_trace_ = true;
134 void WriteChars(const char* output_chars, size_t size) {
135 if (size == 0)
136 return;
138 if (IsValid()) {
139 size_t written = fwrite(output_chars, 1, size, file_);
140 if (written != size) {
141 LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file";
142 CloseFile();
147 void WriteString(const std::string& output_str) {
148 WriteChars(output_str.data(), output_str.size());
151 base::FilePath path_;
152 const FileType file_type_;
153 const bool has_system_trace_;
154 FILE* file_;
155 bool needs_comma_;
156 bool wrote_trace_;
157 bool has_pending_system_trace_;
158 bool wrote_system_trace_;
159 scoped_refptr<base::RefCountedString> pending_system_trace_;
160 DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdioWorker);
163 TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path,
164 FileType file_type,
165 bool has_system_trace)
166 : worker_(new TraceSubscriberStdioWorker(path,
167 file_type,
168 has_system_trace)) {
169 if (has_system_trace)
170 CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type);
171 BrowserThread::PostBlockingPoolSequencedTask(
172 __FILE__, FROM_HERE,
173 base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_));
176 TraceSubscriberStdio::~TraceSubscriberStdio() {
179 void TraceSubscriberStdio::OnEndTracingComplete() {
180 BrowserThread::PostBlockingPoolSequencedTask(
181 __FILE__, FROM_HERE,
182 base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_));
185 void TraceSubscriberStdio::OnTraceDataCollected(
186 const scoped_refptr<base::RefCountedString>& data_ptr) {
187 BrowserThread::PostBlockingPoolSequencedTask(
188 __FILE__, FROM_HERE,
189 base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr));
192 void TraceSubscriberStdio::OnEndSystemTracing(
193 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
194 BrowserThread::PostBlockingPoolSequencedTask(
195 __FILE__, FROM_HERE,
196 base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData,
197 worker_,
198 events_str_ptr));
201 } // namespace content