OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/feedback/tracing_manager.h" | 5 #include "chrome/browser/feedback/tracing_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_util.h" | |
9 #include "base/location.h" | |
10 #include "base/memory/ref_counted_memory.h" | |
11 #include "base/message_loop/message_loop_proxy.h" | |
12 #include "base/prefs/pref_service.h" | 8 #include "base/prefs/pref_service.h" |
13 #include "chrome/browser/browser_process.h" | 9 #include "chrome/browser/browser_process.h" |
14 #include "chrome/browser/feedback/feedback_util.h" | 10 #include "chrome/browser/feedback/feedback_util.h" |
15 #include "chrome/common/pref_names.h" | 11 #include "chrome/common/pref_names.h" |
16 #include "content/public/browser/tracing_controller.h" | 12 #include "content/public/browser/trace_controller.h" |
17 | 13 |
18 namespace { | 14 namespace { |
19 // Only once trace manager can exist at a time. | 15 // Only once trace manager can exist at a time. |
20 TracingManager* g_tracing_manager = NULL; | 16 TracingManager* g_tracing_manager = NULL; |
21 // Trace IDs start at 1 and increase. | 17 // Trace IDs start at 1 and increase. |
22 int g_next_trace_id = 1; | 18 int g_next_trace_id = 1; |
| 19 // Name of the file to store the tracing data as. |
| 20 const base::FilePath::CharType kTracingFilename[] = |
| 21 FILE_PATH_LITERAL("tracing.json"); |
23 } | 22 } |
24 | 23 |
25 TracingManager::TracingManager() | 24 TracingManager::TracingManager() |
26 : current_trace_id_(0), | 25 : current_trace_id_(0), |
27 weak_ptr_factory_(this) { | 26 weak_ptr_factory_(this) { |
28 DCHECK(!g_tracing_manager); | 27 DCHECK(!g_tracing_manager); |
29 g_tracing_manager = this; | 28 g_tracing_manager = this; |
30 StartTracing(); | 29 StartTracing(); |
31 } | 30 } |
32 | 31 |
33 TracingManager::~TracingManager() { | 32 TracingManager::~TracingManager() { |
34 DCHECK(g_tracing_manager == this); | 33 DCHECK(g_tracing_manager == this); |
35 g_tracing_manager = NULL; | 34 g_tracing_manager = NULL; |
36 } | 35 } |
37 | 36 |
38 int TracingManager::RequestTrace() { | 37 int TracingManager::RequestTrace() { |
39 // Return the current trace if one is being collected. | 38 // Return the current trace if one is being collected. |
40 if (current_trace_id_) | 39 if (current_trace_id_) |
41 return current_trace_id_; | 40 return current_trace_id_; |
42 | 41 |
43 current_trace_id_ = g_next_trace_id; | 42 current_trace_id_ = g_next_trace_id; |
44 ++g_next_trace_id; | 43 ++g_next_trace_id; |
45 content::TracingController::GetInstance()->DisableRecording( | 44 content::TraceController::GetInstance()->EndTracingAsync(this); |
46 base::FilePath(), | |
47 base::Bind(&TracingManager::OnTraceDataCollected, | |
48 weak_ptr_factory_.GetWeakPtr())); | |
49 return current_trace_id_; | 45 return current_trace_id_; |
50 } | 46 } |
51 | 47 |
52 bool TracingManager::GetTraceData(int id, const TraceDataCallback& callback) { | 48 bool TracingManager::GetTraceData(int id, const TraceDataCallback& callback) { |
53 // If a trace is being collected currently, send it via callback when | 49 // If a trace is being collected currently, send it via callback when |
54 // complete. | 50 // complete. |
55 if (current_trace_id_) { | 51 if (current_trace_id_) { |
56 // Only allow one trace data request at a time. | 52 // Only allow one trace data request at a time. |
57 if (trace_callback_.is_null()) { | 53 if (trace_callback_.is_null()) { |
58 trace_callback_ = callback; | 54 trace_callback_ = callback; |
(...skipping 14 matching lines...) Expand all Loading... |
73 return true; | 69 return true; |
74 } | 70 } |
75 } | 71 } |
76 | 72 |
77 void TracingManager::DiscardTraceData(int id) { | 73 void TracingManager::DiscardTraceData(int id) { |
78 trace_data_.erase(id); | 74 trace_data_.erase(id); |
79 | 75 |
80 // If the trace is discarded before it is complete, clean up the accumulators. | 76 // If the trace is discarded before it is complete, clean up the accumulators. |
81 if (id == current_trace_id_) { | 77 if (id == current_trace_id_) { |
82 current_trace_id_ = 0; | 78 current_trace_id_ = 0; |
| 79 data_ = ""; |
83 | 80 |
84 // If the trace has already been requested, provide an empty string. | 81 // If the trace has already been requested, provide an empty string. |
85 if (!trace_callback_.is_null()) { | 82 if (!trace_callback_.is_null()) { |
86 trace_callback_.Run(scoped_refptr<base::RefCountedString>()); | 83 trace_callback_.Run(scoped_refptr<base::RefCountedString>()); |
87 trace_callback_.Reset(); | 84 trace_callback_.Reset(); |
88 } | 85 } |
89 } | 86 } |
90 } | 87 } |
91 | 88 |
92 void TracingManager::StartTracing() { | 89 void TracingManager::StartTracing() { |
93 content::TracingController::GetInstance()->EnableRecording( | 90 content::TraceController::GetInstance()->BeginTracing( |
94 "", content::TracingController::DEFAULT_OPTIONS, | 91 this, "-test_*", |
95 content::TracingController::EnableRecordingDoneCallback()); | 92 base::debug::TraceLog::RECORD_CONTINUOUSLY); |
96 } | 93 } |
97 | 94 |
98 void TracingManager::OnTraceDataCollected(const base::FilePath& path) { | 95 void TracingManager::OnEndTracingComplete() { |
99 if (!current_trace_id_) | 96 if (!current_trace_id_) |
100 return; | 97 return; |
101 | 98 |
| 99 data_ = std::string("[") + data_ + "]"; |
| 100 |
102 std::string output_val; | 101 std::string output_val; |
103 feedback_util::ZipFile(path, &output_val); | 102 feedback_util::ZipString( |
104 base::DeleteFile(path, false); | 103 base::FilePath(kTracingFilename), data_, &output_val); |
105 | 104 |
106 scoped_refptr<base::RefCountedString> output( | 105 scoped_refptr<base::RefCountedString> output( |
107 base::RefCountedString::TakeString(&output_val)); | 106 base::RefCountedString::TakeString(&output_val)); |
108 | 107 |
109 trace_data_[current_trace_id_] = output; | 108 trace_data_[current_trace_id_] = output; |
110 | 109 |
111 if (!trace_callback_.is_null()) { | 110 if (!trace_callback_.is_null()) { |
112 trace_callback_.Run(output); | 111 trace_callback_.Run(output); |
113 trace_callback_.Reset(); | 112 trace_callback_.Reset(); |
114 } | 113 } |
115 | 114 |
116 current_trace_id_ = 0; | 115 current_trace_id_ = 0; |
| 116 data_ = ""; |
117 | 117 |
118 // Tracing has to be restarted asynchronous, so the TracingController can | 118 // Tracing has to be restarted asynchronous, so the TracingController can |
119 // clean up. | 119 // clean up. |
120 base::MessageLoopProxy::current()->PostTask( | 120 base::MessageLoopProxy::current()->PostTask( |
121 FROM_HERE, | 121 FROM_HERE, |
122 base::Bind(&TracingManager::StartTracing, | 122 base::Bind(&TracingManager::StartTracing, |
123 weak_ptr_factory_.GetWeakPtr())); | 123 weak_ptr_factory_.GetWeakPtr())); |
124 } | 124 } |
125 | 125 |
| 126 void TracingManager::OnTraceDataCollected( |
| 127 const scoped_refptr<base::RefCountedString>& trace_fragment) { |
| 128 if (current_trace_id_) { |
| 129 if (!data_.empty()) |
| 130 data_ += ","; |
| 131 data_ += trace_fragment->data(); |
| 132 } |
| 133 } |
| 134 |
126 // static | 135 // static |
127 scoped_ptr<TracingManager> TracingManager::Create() { | 136 scoped_ptr<TracingManager> TracingManager::Create() { |
128 if (g_tracing_manager) | 137 if (g_tracing_manager) |
129 return scoped_ptr<TracingManager>(); | 138 return scoped_ptr<TracingManager>(); |
130 return scoped_ptr<TracingManager>(new TracingManager()); | 139 return scoped_ptr<TracingManager>(new TracingManager()); |
131 } | 140 } |
132 | 141 |
133 TracingManager* TracingManager::Get() { | 142 TracingManager* TracingManager::Get() { |
134 return g_tracing_manager; | 143 return g_tracing_manager; |
135 } | 144 } |
OLD | NEW |