OLD | NEW |
| (Empty) |
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 | |
5 #include "content/browser/tracing/background_tracing_manager_impl.h" | |
6 | |
7 #include "base/macros.h" | |
8 #include "content/public/browser/background_tracing_preemptive_config.h" | |
9 #include "content/public/browser/background_tracing_reactive_config.h" | |
10 #include "content/public/browser/browser_thread.h" | |
11 | |
12 namespace content { | |
13 | |
14 namespace { | |
15 | |
16 base::LazyInstance<BackgroundTracingManagerImpl>::Leaky g_controller = | |
17 LAZY_INSTANCE_INITIALIZER; | |
18 | |
19 } // namespace | |
20 | |
21 BackgroundTracingManagerImpl::TraceDataEndpointWrapper:: | |
22 TraceDataEndpointWrapper(base::Callback< | |
23 void(scoped_refptr<base::RefCountedString>)> done_callback) | |
24 : done_callback_(done_callback) { | |
25 } | |
26 | |
27 BackgroundTracingManagerImpl::TraceDataEndpointWrapper:: | |
28 ~TraceDataEndpointWrapper() { | |
29 } | |
30 | |
31 void BackgroundTracingManagerImpl::TraceDataEndpointWrapper:: | |
32 ReceiveTraceFinalContents(const std::string& file_contents) { | |
33 std::string tmp = file_contents; | |
34 scoped_refptr<base::RefCountedString> contents_ptr = | |
35 base::RefCountedString::TakeString(&tmp); | |
36 | |
37 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
38 base::Bind(done_callback_, contents_ptr)); | |
39 } | |
40 | |
41 BackgroundTracingManager* BackgroundTracingManager::GetInstance() { | |
42 return BackgroundTracingManagerImpl::GetInstance(); | |
43 } | |
44 | |
45 BackgroundTracingManagerImpl* BackgroundTracingManagerImpl::GetInstance() { | |
46 return g_controller.Pointer(); | |
47 } | |
48 | |
49 BackgroundTracingManagerImpl::BackgroundTracingManagerImpl() | |
50 : is_gathering_(false), | |
51 is_tracing_(false), | |
52 requires_anonymized_data_(true), | |
53 trigger_handle_ids_(0) { | |
54 data_endpoint_wrapper_ = new TraceDataEndpointWrapper( | |
55 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeStarted, | |
56 base::Unretained(this))); | |
57 } | |
58 | |
59 BackgroundTracingManagerImpl::~BackgroundTracingManagerImpl() { | |
60 NOTREACHED(); | |
61 } | |
62 | |
63 void BackgroundTracingManagerImpl::WhenIdle( | |
64 base::Callback<void()> idle_callback) { | |
65 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
66 idle_callback_ = idle_callback; | |
67 } | |
68 | |
69 bool BackgroundTracingManagerImpl::IsSupportedConfig( | |
70 BackgroundTracingConfig* config) { | |
71 // No config is just fine, we just don't do anything. | |
72 if (!config) | |
73 return true; | |
74 | |
75 // TODO(simonhatch): Implement reactive tracing path. | |
76 if (config->mode != BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) | |
77 return false; | |
78 | |
79 // TODO(fmeawad): Implement uma triggers. | |
80 BackgroundTracingPreemptiveConfig* preemptive_config = | |
81 static_cast<BackgroundTracingPreemptiveConfig*>(config); | |
82 const std::vector<BackgroundTracingPreemptiveConfig::MonitoringRule>& | |
83 configs = preemptive_config->configs; | |
84 for (size_t i = 0; i < configs.size(); ++i) { | |
85 if (configs[i].type != | |
86 BackgroundTracingPreemptiveConfig::MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED) | |
87 return false; | |
88 } | |
89 | |
90 return true; | |
91 } | |
92 | |
93 bool BackgroundTracingManagerImpl::SetActiveScenario( | |
94 scoped_ptr<BackgroundTracingConfig> config, | |
95 const BackgroundTracingManager::ReceiveCallback& receive_callback, | |
96 bool requires_anonymized_data) { | |
97 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
98 if (is_tracing_) | |
99 return false; | |
100 | |
101 if (!IsSupportedConfig(config.get())) | |
102 return false; | |
103 | |
104 // No point in tracing if there's nowhere to send it. | |
105 if (config && receive_callback.is_null()) | |
106 return false; | |
107 | |
108 config_ = config.Pass(); | |
109 receive_callback_ = receive_callback; | |
110 requires_anonymized_data_ = requires_anonymized_data; | |
111 | |
112 EnableRecordingIfConfigNeedsIt(); | |
113 | |
114 return true; | |
115 } | |
116 | |
117 void BackgroundTracingManagerImpl::EnableRecordingIfConfigNeedsIt() { | |
118 if (!config_) | |
119 return; | |
120 | |
121 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) { | |
122 EnableRecording(GetCategoryFilterForCategoryPreset( | |
123 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get()) | |
124 ->category_preset)); | |
125 } else { | |
126 // TODO(simonhatch): Implement reactive tracing path. | |
127 NOTREACHED(); | |
128 } | |
129 } | |
130 | |
131 bool BackgroundTracingManagerImpl::IsAbleToTriggerTracing( | |
132 TriggerHandle handle) const { | |
133 if (!config_) | |
134 return false; | |
135 | |
136 // If the last trace is still uploading, we don't allow a new one to trigger. | |
137 if (is_gathering_) | |
138 return false; | |
139 | |
140 if (!IsTriggerHandleValid(handle)) { | |
141 return false; | |
142 } | |
143 | |
144 std::string trigger_name = GetTriggerNameFromHandle(handle); | |
145 | |
146 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) { | |
147 BackgroundTracingPreemptiveConfig* preemptive_config = | |
148 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get()); | |
149 | |
150 const std::vector<BackgroundTracingPreemptiveConfig::MonitoringRule>& | |
151 configs = preemptive_config->configs; | |
152 | |
153 for (size_t i = 0; i < configs.size(); ++i) { | |
154 if (configs[i].type != BackgroundTracingPreemptiveConfig:: | |
155 MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED) | |
156 continue; | |
157 | |
158 if (trigger_name == configs[i].named_trigger_info.trigger_name) { | |
159 return true; | |
160 } | |
161 } | |
162 } else { | |
163 // TODO(simonhatch): Implement reactive path. | |
164 NOTREACHED(); | |
165 } | |
166 | |
167 return false; | |
168 } | |
169 | |
170 void BackgroundTracingManagerImpl::TriggerNamedEvent( | |
171 BackgroundTracingManagerImpl::TriggerHandle handle, | |
172 StartedFinalizingCallback callback) { | |
173 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | |
174 content::BrowserThread::PostTask( | |
175 content::BrowserThread::UI, FROM_HERE, | |
176 base::Bind(&BackgroundTracingManagerImpl::TriggerNamedEvent, | |
177 base::Unretained(this), handle, callback)); | |
178 return; | |
179 } | |
180 | |
181 if (!IsAbleToTriggerTracing(handle)) { | |
182 if (!callback.is_null()) | |
183 callback.Run(false); | |
184 return; | |
185 } | |
186 | |
187 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) { | |
188 BeginFinalizing(callback); | |
189 } else { | |
190 // TODO(simonhatch): Implement reactive tracing path. | |
191 NOTREACHED(); | |
192 } | |
193 } | |
194 | |
195 BackgroundTracingManagerImpl::TriggerHandle | |
196 BackgroundTracingManagerImpl::RegisterTriggerType(const char* trigger_name) { | |
197 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
198 | |
199 trigger_handle_ids_ += 1; | |
200 | |
201 trigger_handles_.insert( | |
202 std::pair<TriggerHandle, std::string>(trigger_handle_ids_, trigger_name)); | |
203 | |
204 return static_cast<TriggerHandle>(trigger_handle_ids_); | |
205 } | |
206 | |
207 bool BackgroundTracingManagerImpl::IsTriggerHandleValid( | |
208 BackgroundTracingManager::TriggerHandle handle) const { | |
209 return trigger_handles_.find(handle) != trigger_handles_.end(); | |
210 } | |
211 | |
212 std::string BackgroundTracingManagerImpl::GetTriggerNameFromHandle( | |
213 BackgroundTracingManager::TriggerHandle handle) const { | |
214 CHECK(IsTriggerHandleValid(handle)); | |
215 return trigger_handles_.find(handle)->second; | |
216 } | |
217 | |
218 void BackgroundTracingManagerImpl::GetTriggerNameList( | |
219 std::vector<std::string>* trigger_names) { | |
220 for (std::map<TriggerHandle, std::string>::iterator it = | |
221 trigger_handles_.begin(); | |
222 it != trigger_handles_.end(); ++it) | |
223 trigger_names->push_back(it->second); | |
224 } | |
225 | |
226 void BackgroundTracingManagerImpl::InvalidateTriggerHandlesForTesting() { | |
227 trigger_handles_.clear(); | |
228 } | |
229 | |
230 void BackgroundTracingManagerImpl::EnableRecording( | |
231 base::trace_event::CategoryFilter category_filter) { | |
232 is_tracing_ = TracingController::GetInstance()->EnableRecording( | |
233 category_filter, | |
234 base::trace_event::TraceOptions(base::trace_event::RECORD_CONTINUOUSLY), | |
235 TracingController::EnableRecordingDoneCallback()); | |
236 } | |
237 | |
238 void BackgroundTracingManagerImpl::OnFinalizeStarted( | |
239 scoped_refptr<base::RefCountedString> file_contents) { | |
240 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
241 | |
242 if (!receive_callback_.is_null()) | |
243 receive_callback_.Run( | |
244 file_contents.get(), | |
245 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete, | |
246 base::Unretained(this))); | |
247 } | |
248 | |
249 void BackgroundTracingManagerImpl::OnFinalizeComplete() { | |
250 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
251 BrowserThread::PostTask( | |
252 BrowserThread::UI, FROM_HERE, | |
253 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete, | |
254 base::Unretained(this))); | |
255 return; | |
256 } | |
257 | |
258 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
259 | |
260 is_gathering_ = false; | |
261 | |
262 if (!idle_callback_.is_null()) | |
263 idle_callback_.Run(); | |
264 | |
265 // Now that a trace has completed, we may need to enable recording again. | |
266 EnableRecordingIfConfigNeedsIt(); | |
267 } | |
268 | |
269 void BackgroundTracingManagerImpl::BeginFinalizing( | |
270 StartedFinalizingCallback callback) { | |
271 is_gathering_ = true; | |
272 is_tracing_ = false; | |
273 | |
274 content::TracingController::GetInstance()->DisableRecording( | |
275 content::TracingController::CreateCompressedStringSink( | |
276 data_endpoint_wrapper_)); | |
277 | |
278 if (!callback.is_null()) | |
279 callback.Run(true); | |
280 } | |
281 | |
282 base::trace_event::CategoryFilter | |
283 BackgroundTracingManagerImpl::GetCategoryFilterForCategoryPreset( | |
284 BackgroundTracingConfig::CategoryPreset preset) const { | |
285 switch (preset) { | |
286 case BackgroundTracingConfig::CategoryPreset::BENCHMARK: | |
287 return base::trace_event::CategoryFilter( | |
288 "benchmark," | |
289 "disabled-by-default-toplevel.flow," | |
290 "disabled-by-default-ipc.flow"); | |
291 case BackgroundTracingConfig::CategoryPreset::BENCHMARK_DEEP: | |
292 return base::trace_event::CategoryFilter( | |
293 "*,disabled-by-default-blink.debug.layout"); | |
294 } | |
295 NOTREACHED(); | |
296 return base::trace_event::CategoryFilter(); | |
297 } | |
298 | |
299 BackgroundTracingConfig* BackgroundTracingConfig::FromDict( | |
300 const base::DictionaryValue* dict) { | |
301 // TODO(simonhatch): Implement this. | |
302 CHECK(false); | |
303 return NULL; | |
304 } | |
305 | |
306 void BackgroundTracingConfig::IntoDict(const BackgroundTracingConfig* config, | |
307 base::DictionaryValue* dict) { | |
308 // TODO(simonhatch): Implement this. | |
309 CHECK(false); | |
310 } | |
311 | |
312 } // namspace content | |
OLD | NEW |