Chromium Code Reviews| 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 |