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 "content/browser/tracing/tracing_controller_impl.h" | 5 #include "content/browser/tracing/tracing_controller_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/json/string_escape.h" | 10 #include "base/json/string_escape.h" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "content/browser/tracing/trace_message_filter.h" | 12 #include "content/browser/tracing/trace_message_filter.h" |
13 #include "content/browser/tracing/tracing_ui.h" | 13 #include "content/browser/tracing/tracing_ui.h" |
14 #include "content/common/child_process_messages.h" | 14 #include "content/common/child_process_messages.h" |
15 #include "content/public/browser/browser_message_filter.h" | 15 #include "content/public/browser/browser_message_filter.h" |
16 #include "content/public/common/content_switches.h" | 16 #include "content/public/common/content_switches.h" |
17 | 17 |
18 #if defined(OS_CHROMEOS) | 18 #if defined(OS_CHROMEOS) |
19 #include "chromeos/dbus/dbus_thread_manager.h" | 19 #include "chromeos/dbus/dbus_thread_manager.h" |
20 #include "chromeos/dbus/debug_daemon_client.h" | 20 #include "chromeos/dbus/debug_daemon_client.h" |
21 #endif | 21 #endif |
22 | 22 |
23 #if defined(OS_WIN) | |
24 #include "base/values.h" | |
25 #include "base/json/json_string_value_serializer.h" | |
26 #include "base/win/event_trace_controller.h" | |
27 #include "base/win/event_trace_consumer.h" | |
28 #endif | |
29 | |
23 using base::debug::TraceLog; | 30 using base::debug::TraceLog; |
24 | 31 |
25 namespace content { | 32 namespace content { |
26 | 33 |
27 namespace { | 34 namespace { |
28 | 35 |
29 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = | 36 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = |
30 LAZY_INSTANCE_INITIALIZER; | 37 LAZY_INSTANCE_INITIALIZER; |
31 | 38 |
39 #if defined(OS_WIN) | |
40 | |
41 std::string GuidToString(const GUID& guid) { | |
42 return base::StringPrintf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", | |
43 guid.Data1, guid.Data2, guid.Data3, | |
44 guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], | |
45 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); | |
46 } | |
47 | |
48 class EtwSystemEventConsumer : | |
49 public base::win::EtwTraceConsumerBase<EtwSystemEventConsumer> { | |
50 public: | |
51 typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&)> | |
52 OutputCallback; | |
53 | |
54 EtwSystemEventConsumer() : thread_("EtwConsumerThread") { | |
55 thread_.Start(); | |
56 } | |
57 | |
58 void RequestStartSystemTracing() { | |
59 events_.reset(new base::ListValue()); | |
60 thread_.message_loop()->PostTask( | |
61 FROM_HERE, | |
62 base::Bind(&EtwSystemEventConsumer::TraceAndConsumeOnThread, | |
63 base::Unretained(this))); | |
64 } | |
65 | |
66 void RequestStopSystemTracing(const OutputCallback& callback) { | |
67 thread_.message_loop()->PostTask(FROM_HERE, | |
68 base::Bind(&EtwSystemEventConsumer::StopSystemTracingOnThread, | |
69 base::Unretained(this), callback)); | |
70 } | |
71 | |
72 void AppendEventToBuffer(EVENT_TRACE* event) { | |
fdoray
2014/02/19 16:18:08
Should be private.
etienneb
2014/02/19 17:14:52
Done.
| |
73 using base::Value; | |
74 using base::StringPrintf; | |
75 | |
76 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); | |
77 | |
78 // Add header fields to the event. | |
79 value->Set("ts", base::Value::CreateStringValue( | |
80 StringPrintf("%08X%08X", | |
81 event->Header.TimeStamp.HighPart, | |
82 event->Header.TimeStamp.LowPart))); | |
83 | |
84 value->Set("guid", base::Value::CreateStringValue( | |
85 GuidToString(event->Header.Guid))); | |
86 | |
87 // TODO(etienneb): CreateIntegerValue are deprecated. | |
88 value->Set("op", Value::CreateIntegerValue(event->Header.Class.Type)); | |
89 value->Set("ver", Value::CreateIntegerValue(event->Header.Class.Version)); | |
90 value->Set("pid", Value::CreateIntegerValue(event->Header.ProcessId)); | |
91 value->Set("tid", Value::CreateIntegerValue(event->Header.ProcessId)); | |
92 value->Set("cpu", Value::CreateIntegerValue( | |
93 event->BufferContext.ProcessorNumber)); | |
94 | |
95 // TODO(etienneb): fix it!!!!! | |
96 value->Set("is64", Value::CreateIntegerValue(1)); | |
97 | |
98 // Encode the payload bytes in hexadecimal. | |
99 std::string payload = | |
100 StringToLowerASCII(base::HexEncode(event->MofData, event->MofLength)); | |
fdoray
2014/02/19 16:18:08
Too much indentation. Should be 4 spaces.
etienneb
2014/02/19 17:14:52
Done.
| |
101 value->Set("payload", base::Value::CreateStringValue(payload)); | |
nduca
2014/02/18 22:17:46
oh also should base64 encode?
etienneb
2014/02/19 17:14:52
Done.
| |
102 | |
103 // Append it to the events buffer. | |
104 events_->Append(value.release()); | |
105 } | |
106 | |
107 static void ProcessEvent(EVENT_TRACE* event); | |
108 static EtwSystemEventConsumer* Get(); | |
109 | |
110 bool StartNTKernelSessionTracing() { | |
111 // Enabled flags (tracing facilities). | |
112 uint32 enabled_flags = EVENT_TRACE_FLAG_IMAGE_LOAD | | |
113 EVENT_TRACE_FLAG_PROCESS | | |
114 EVENT_TRACE_FLAG_THREAD | | |
115 EVENT_TRACE_FLAG_CSWITCH; | |
116 | |
117 EVENT_TRACE_PROPERTIES& p = *properties_.get(); | |
118 p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; | |
119 p.FlushTimer = 1; // flush every second. | |
120 p.BufferSize = 16; // 16 K buffers. | |
dsinclair
2014/02/19 16:29:39
Should these be moved to constants instead of havi
etienneb
2014/02/19 17:14:52
Done.
| |
121 p.LogFileNameOffset = 0; | |
122 p.EnableFlags = enabled_flags; | |
123 | |
124 HRESULT hr = base::win::EtwTraceController::Start( | |
125 KERNEL_LOGGER_NAME, &properties_, &session_handle_); | |
126 if (FAILED(hr)) { | |
127 VLOG(1) << "StartRealtimeSession() failed with " << hr << "."; | |
128 return false; | |
129 } | |
130 | |
131 return true; | |
132 } | |
133 | |
134 bool StopNTKernelSessionTracing() { | |
135 HRESULT hr = base::win::EtwTraceController::Stop( | |
136 KERNEL_LOGGER_NAME, &properties_); | |
137 return SUCCEEDED(hr); | |
138 } | |
139 | |
140 private: | |
141 | |
fdoray
2014/02/19 16:18:08
No empty line.
etienneb
2014/02/19 17:14:52
Done.
| |
142 void TraceAndConsumeOnThread() { | |
143 HRESULT hr = OpenRealtimeSession(KERNEL_LOGGER_NAME); | |
144 if (FAILED(hr)) | |
145 return; | |
146 Consume(); | |
147 Close(); | |
148 } | |
149 | |
150 void StopSystemTracingOnThread(const OutputCallback& callback) { | |
151 // Add the header information to the stream. | |
152 scoped_ptr<base::DictionaryValue> header(new base::DictionaryValue()); | |
153 header->Set("name", base::Value::CreateStringValue("ETW")); | |
154 header->Set("content", events_.release()); | |
155 | |
156 // Serialize the results as a JSon string. | |
157 std::string output; | |
158 JSONStringValueSerializer serializer(&output); | |
159 serializer.set_pretty_print(true); | |
160 serializer.Serialize(*header.get()); | |
161 | |
162 // Pass the result to the UI Thread. | |
163 scoped_refptr<base::RefCountedString> result = | |
164 base::RefCountedString::TakeString(&output); | |
165 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
166 base::Bind(callback, result)); | |
167 } | |
168 | |
169 scoped_ptr<base::ListValue> events_; | |
170 base::Thread thread_; | |
171 TRACEHANDLE session_handle_; | |
172 base::win::EtwTraceProperties properties_; | |
173 }; | |
174 | |
175 base::LazyInstance<EtwSystemEventConsumer>::Leaky g_etw_consumer = | |
176 LAZY_INSTANCE_INITIALIZER; | |
177 | |
178 EtwSystemEventConsumer* EtwSystemEventConsumer::Get() { | |
179 return g_etw_consumer.Pointer(); | |
180 } | |
181 | |
182 void EtwSystemEventConsumer::ProcessEvent(EVENT_TRACE* event) { | |
183 EtwSystemEventConsumer::Get()->AppendEventToBuffer(event); | |
184 } | |
185 | |
186 #endif // OS_WIN | |
187 | |
32 } // namespace | 188 } // namespace |
33 | 189 |
34 TracingController* TracingController::GetInstance() { | 190 TracingController* TracingController::GetInstance() { |
35 return TracingControllerImpl::GetInstance(); | 191 return TracingControllerImpl::GetInstance(); |
36 } | 192 } |
37 | 193 |
38 class TracingControllerImpl::ResultFile { | 194 class TracingControllerImpl::ResultFile { |
39 public: | 195 public: |
40 explicit ResultFile(const base::FilePath& path); | 196 explicit ResultFile(const base::FilePath& path); |
41 void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) { | 197 void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
122 void TracingControllerImpl::ResultFile::CloseTask( | 278 void TracingControllerImpl::ResultFile::CloseTask( |
123 const base::Closure& callback) { | 279 const base::Closure& callback) { |
124 if (!file_) | 280 if (!file_) |
125 return; | 281 return; |
126 | 282 |
127 const char* trailevents = "]"; | 283 const char* trailevents = "]"; |
128 size_t written = fwrite(trailevents, strlen(trailevents), 1, file_); | 284 size_t written = fwrite(trailevents, strlen(trailevents), 1, file_); |
129 DCHECK(written == 1); | 285 DCHECK(written == 1); |
130 | 286 |
131 if (system_trace_) { | 287 if (system_trace_) { |
288 #if defined(OS_WIN) | |
289 // TODO(etienneb): This is ugly patch on windows. We should keep Value for | |
290 // all OS instead of String to represent system traces. | |
291 std::string json_string = system_trace_->data(); | |
292 #else | |
132 std::string json_string = base::GetQuotedJSONString(system_trace_->data()); | 293 std::string json_string = base::GetQuotedJSONString(system_trace_->data()); |
294 #endif | |
133 | 295 |
134 const char* systemTraceHead = ", \"systemTraceEvents\": "; | 296 const char* systemTraceHead = ",\n\"systemTraceEvents\": "; |
135 written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_); | 297 written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_); |
136 DCHECK(written == 1); | 298 DCHECK(written == 1); |
137 | 299 |
138 written = fwrite(json_string.data(), json_string.size(), 1, file_); | 300 written = fwrite(json_string.data(), json_string.size(), 1, file_); |
139 DCHECK(written == 1); | 301 DCHECK(written == 1); |
140 | 302 |
141 system_trace_ = NULL; | 303 system_trace_ = NULL; |
142 } | 304 } |
143 | 305 |
144 const char* trailout = "}"; | 306 const char* trailout = "}"; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
229 if (pending_get_categories_done_callback_.is_null()) | 391 if (pending_get_categories_done_callback_.is_null()) |
230 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); | 392 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); |
231 #endif | 393 #endif |
232 | 394 |
233 options_ = options; | 395 options_ = options; |
234 int trace_options = (options & RECORD_CONTINUOUSLY) ? | 396 int trace_options = (options & RECORD_CONTINUOUSLY) ? |
235 TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL; | 397 TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL; |
236 if (options & ENABLE_SAMPLING) { | 398 if (options & ENABLE_SAMPLING) { |
237 trace_options |= TraceLog::ENABLE_SAMPLING; | 399 trace_options |= TraceLog::ENABLE_SAMPLING; |
238 } | 400 } |
401 | |
239 #if defined(OS_CHROMEOS) | 402 #if defined(OS_CHROMEOS) |
240 if (options & ENABLE_SYSTRACE) { | 403 if (options & ENABLE_SYSTRACE) { |
241 DCHECK(!is_system_tracing_); | 404 DCHECK(!is_system_tracing_); |
242 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> | 405 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> |
243 StartSystemTracing(); | 406 StartSystemTracing(); |
244 is_system_tracing_ = true; | 407 is_system_tracing_ = true; |
245 } | 408 } |
246 #endif | 409 #endif |
247 | 410 |
248 #if defined(OS_WIN) | 411 #if defined(OS_WIN) |
249 if (options & ENABLE_SYSTRACE) { | 412 if (options & ENABLE_SYSTRACE) { |
250 DCHECK(!is_system_tracing_); | 413 DCHECK(!is_system_tracing_); |
251 is_system_tracing_ = true; | 414 is_system_tracing_ = |
415 EtwSystemEventConsumer::Get()->StartNTKernelSessionTracing(); | |
416 EtwSystemEventConsumer::Get()->RequestStartSystemTracing(); | |
252 } | 417 } |
253 #endif | 418 #endif |
254 | 419 |
255 base::Closure on_enable_recording_done_callback = | 420 base::Closure on_enable_recording_done_callback = |
256 base::Bind(&TracingControllerImpl::OnEnableRecordingDone, | 421 base::Bind(&TracingControllerImpl::OnEnableRecordingDone, |
257 base::Unretained(this), | 422 base::Unretained(this), |
258 category_filter, trace_options, callback); | 423 category_filter, trace_options, callback); |
259 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 424 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
260 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, | 425 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, |
261 base::Unretained(this), | 426 base::Unretained(this), |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
685 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> | 850 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> |
686 RequestStopSystemTracing( | 851 RequestStopSystemTracing( |
687 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, | 852 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, |
688 base::Unretained(this))); | 853 base::Unretained(this))); |
689 return; | 854 return; |
690 } | 855 } |
691 #endif | 856 #endif |
692 | 857 |
693 #if defined(OS_WIN) | 858 #if defined(OS_WIN) |
694 if (is_system_tracing_) { | 859 if (is_system_tracing_) { |
860 // Disable system tracing. | |
861 EtwSystemEventConsumer::Get()->StopNTKernelSessionTracing(); | |
695 is_system_tracing_ = false; | 862 is_system_tracing_ = false; |
863 | |
864 // Request events to be flushed. | |
865 EtwSystemEventConsumer::Get()->RequestStopSystemTracing( | |
866 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, | |
867 base::Unretained(this))); | |
868 return; | |
696 } | 869 } |
697 #endif | 870 #endif |
698 | 871 |
699 // Trigger callback if one is set. | 872 // Trigger callback if one is set. |
700 if (!pending_get_categories_done_callback_.is_null()) { | 873 if (!pending_get_categories_done_callback_.is_null()) { |
701 pending_get_categories_done_callback_.Run(known_category_groups_); | 874 pending_get_categories_done_callback_.Run(known_category_groups_); |
702 pending_get_categories_done_callback_.Reset(); | 875 pending_get_categories_done_callback_.Reset(); |
703 } else if (result_file_) { | 876 } else if (result_file_) { |
704 result_file_->Close( | 877 result_file_->Close( |
705 base::Bind(&TracingControllerImpl::OnResultFileClosed, | 878 base::Bind(&TracingControllerImpl::OnResultFileClosed, |
706 base::Unretained(this))); | 879 base::Unretained(this))); |
707 } | 880 } |
708 } | 881 } |
709 | 882 |
710 void TracingControllerImpl::OnResultFileClosed() { | 883 void TracingControllerImpl::OnResultFileClosed() { |
711 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 884 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
712 | 885 |
713 if (!result_file_) | 886 if (!result_file_) |
714 return; | 887 return; |
715 | 888 |
716 if (!pending_disable_recording_done_callback_.is_null()) { | 889 if (!pending_disable_recording_done_callback_.is_null()) { |
717 pending_disable_recording_done_callback_.Run(result_file_->path()); | 890 pending_disable_recording_done_callback_.Run(result_file_->path()); |
718 pending_disable_recording_done_callback_.Reset(); | 891 pending_disable_recording_done_callback_.Reset(); |
719 } | 892 } |
720 result_file_.reset(); | 893 result_file_.reset(); |
721 } | 894 } |
722 | 895 |
723 #if defined(OS_CHROMEOS) | 896 #if defined(OS_CHROMEOS) || defined(OS_WIN) |
724 void TracingControllerImpl::OnEndSystemTracingAcked( | 897 void TracingControllerImpl::OnEndSystemTracingAcked( |
725 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | 898 const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
727 | 900 |
728 if (result_file_) | 901 if (result_file_) |
729 result_file_->WriteSystemTrace(events_str_ptr); | 902 result_file_->WriteSystemTrace(events_str_ptr); |
730 | 903 |
731 DCHECK(!is_system_tracing_); | 904 DCHECK(!is_system_tracing_); |
732 OnDisableRecordingComplete(); | 905 OnDisableRecordingComplete(); |
733 } | 906 } |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
904 is_monitoring_ = is_monitoring; | 1077 is_monitoring_ = is_monitoring; |
905 #if !defined(OS_ANDROID) | 1078 #if !defined(OS_ANDROID) |
906 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin(); | 1079 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin(); |
907 it != tracing_uis_.end(); it++) { | 1080 it != tracing_uis_.end(); it++) { |
908 (*it)->OnMonitoringStateChanged(is_monitoring); | 1081 (*it)->OnMonitoringStateChanged(is_monitoring); |
909 } | 1082 } |
910 #endif | 1083 #endif |
911 } | 1084 } |
912 | 1085 |
913 } // namespace content | 1086 } // namespace content |
OLD | NEW |