OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 | |
5 #include "content/browser/tracing/tracing_controller_impl.h" | 4 #include "content/browser/tracing/tracing_controller_impl.h" |
6 | 5 |
7 #include "base/bind.h" | 6 #include "base/bind.h" |
8 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
9 #include "base/file_util.h" | 8 #include "base/file_util.h" |
10 #include "base/json/string_escape.h" | 9 #include "base/json/string_escape.h" |
11 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
12 #include "content/browser/tracing/trace_message_filter.h" | 11 #include "content/browser/tracing/trace_message_filter.h" |
13 #include "content/browser/tracing/tracing_ui.h" | 12 #include "content/browser/tracing/tracing_ui.h" |
14 #include "content/common/child_process_messages.h" | 13 #include "content/common/child_process_messages.h" |
15 #include "content/public/browser/browser_message_filter.h" | 14 #include "content/public/browser/browser_message_filter.h" |
16 #include "content/public/common/content_switches.h" | 15 #include "content/public/common/content_switches.h" |
17 | 16 |
18 #if defined(OS_CHROMEOS) | 17 #if defined(OS_CHROMEOS) |
19 #include "chromeos/dbus/dbus_thread_manager.h" | 18 #include "chromeos/dbus/dbus_thread_manager.h" |
20 #include "chromeos/dbus/debug_daemon_client.h" | 19 #include "chromeos/dbus/debug_daemon_client.h" |
21 #endif | 20 #endif |
22 | 21 |
| 22 #if defined(OS_WIN) |
| 23 #include "content/browser/tracing/etw_system_event_consumer_win.h" |
| 24 #endif |
| 25 |
23 using base::debug::TraceLog; | 26 using base::debug::TraceLog; |
24 | 27 |
25 namespace content { | 28 namespace content { |
26 | 29 |
27 namespace { | 30 namespace { |
28 | 31 |
29 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = | 32 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = |
30 LAZY_INSTANCE_INITIALIZER; | 33 LAZY_INSTANCE_INITIALIZER; |
31 | 34 |
32 } // namespace | 35 } // namespace |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 const char* preamble = "{\"traceEvents\": ["; | 97 const char* preamble = "{\"traceEvents\": ["; |
95 size_t written = fwrite(preamble, strlen(preamble), 1, file_); | 98 size_t written = fwrite(preamble, strlen(preamble), 1, file_); |
96 DCHECK(written == 1); | 99 DCHECK(written == 1); |
97 } | 100 } |
98 | 101 |
99 void TracingControllerImpl::ResultFile::WriteTask( | 102 void TracingControllerImpl::ResultFile::WriteTask( |
100 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | 103 const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
101 if (!file_ || !events_str_ptr->data().size()) | 104 if (!file_ || !events_str_ptr->data().size()) |
102 return; | 105 return; |
103 | 106 |
104 // If there is already a result in the file, then put a commma | 107 // If there is already a result in the file, then put a comma |
105 // before the next batch of results. | 108 // before the next batch of results. |
106 if (has_at_least_one_result_) { | 109 if (has_at_least_one_result_) { |
107 size_t written = fwrite(",", 1, 1, file_); | 110 size_t written = fwrite(",", 1, 1, file_); |
108 DCHECK(written == 1); | 111 DCHECK(written == 1); |
109 } | 112 } |
110 has_at_least_one_result_ = true; | 113 has_at_least_one_result_ = true; |
111 size_t written = fwrite(events_str_ptr->data().c_str(), | 114 size_t written = fwrite(events_str_ptr->data().c_str(), |
112 events_str_ptr->data().size(), 1, | 115 events_str_ptr->data().size(), 1, |
113 file_); | 116 file_); |
114 DCHECK(written == 1); | 117 DCHECK(written == 1); |
115 } | 118 } |
116 | 119 |
117 void TracingControllerImpl::ResultFile::WriteSystemTraceTask( | 120 void TracingControllerImpl::ResultFile::WriteSystemTraceTask( |
118 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | 121 const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
119 system_trace_ = events_str_ptr; | 122 system_trace_ = events_str_ptr; |
120 } | 123 } |
121 | 124 |
122 void TracingControllerImpl::ResultFile::CloseTask( | 125 void TracingControllerImpl::ResultFile::CloseTask( |
123 const base::Closure& callback) { | 126 const base::Closure& callback) { |
124 if (!file_) | 127 if (!file_) |
125 return; | 128 return; |
126 | 129 |
127 const char* trailevents = "]"; | 130 const char* trailevents = "]"; |
128 size_t written = fwrite(trailevents, strlen(trailevents), 1, file_); | 131 size_t written = fwrite(trailevents, strlen(trailevents), 1, file_); |
129 DCHECK(written == 1); | 132 DCHECK(written == 1); |
130 | 133 |
131 if (system_trace_) { | 134 if (system_trace_) { |
| 135 #if defined(OS_WIN) |
| 136 // The Windows kernel events are kept into a JSon format stored as string |
| 137 // and must not be escaped. |
| 138 std::string json_string = system_trace_->data(); |
| 139 #else |
132 std::string json_string = base::GetQuotedJSONString(system_trace_->data()); | 140 std::string json_string = base::GetQuotedJSONString(system_trace_->data()); |
| 141 #endif |
133 | 142 |
134 const char* systemTraceHead = ", \"systemTraceEvents\": "; | 143 const char* systemTraceHead = ",\n\"systemTraceEvents\": "; |
135 written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_); | 144 written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_); |
136 DCHECK(written == 1); | 145 DCHECK(written == 1); |
137 | 146 |
138 written = fwrite(json_string.data(), json_string.size(), 1, file_); | 147 written = fwrite(json_string.data(), json_string.size(), 1, file_); |
139 DCHECK(written == 1); | 148 DCHECK(written == 1); |
140 | 149 |
141 system_trace_ = NULL; | 150 system_trace_ = NULL; |
142 } | 151 } |
143 | 152 |
144 const char* trailout = "}"; | 153 const char* trailout = "}"; |
145 written = fwrite(trailout, strlen(trailout), 1, file_); | 154 written = fwrite(trailout, strlen(trailout), 1, file_); |
146 DCHECK(written == 1); | 155 DCHECK(written == 1); |
147 base::CloseFile(file_); | 156 base::CloseFile(file_); |
148 file_ = NULL; | 157 file_ = NULL; |
149 | 158 |
150 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | 159 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); |
151 } | 160 } |
152 | 161 |
153 | 162 |
154 TracingControllerImpl::TracingControllerImpl() : | 163 TracingControllerImpl::TracingControllerImpl() : |
155 pending_disable_recording_ack_count_(0), | 164 pending_disable_recording_ack_count_(0), |
156 pending_capture_monitoring_snapshot_ack_count_(0), | 165 pending_capture_monitoring_snapshot_ack_count_(0), |
157 pending_trace_buffer_percent_full_ack_count_(0), | 166 pending_trace_buffer_percent_full_ack_count_(0), |
158 maximum_trace_buffer_percent_full_(0), | 167 maximum_trace_buffer_percent_full_(0), |
159 // Tracing may have been enabled by ContentMainRunner if kTraceStartup | 168 // Tracing may have been enabled by ContentMainRunner if kTraceStartup |
160 // is specified in command line. | 169 // is specified in command line. |
161 #if defined(OS_CHROMEOS) | 170 #if defined(OS_CHROMEOS) || defined(OS_WIN) |
162 is_system_tracing_(false), | 171 is_system_tracing_(false), |
163 #endif | 172 #endif |
164 is_recording_(TraceLog::GetInstance()->IsEnabled()), | 173 is_recording_(TraceLog::GetInstance()->IsEnabled()), |
165 is_monitoring_(false) { | 174 is_monitoring_(false) { |
166 } | 175 } |
167 | 176 |
168 TracingControllerImpl::~TracingControllerImpl() { | 177 TracingControllerImpl::~TracingControllerImpl() { |
169 // This is a Leaky instance. | 178 // This is a Leaky instance. |
170 NOTREACHED(); | 179 NOTREACHED(); |
171 } | 180 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 | 236 |
228 #if defined(OS_ANDROID) | 237 #if defined(OS_ANDROID) |
229 if (pending_get_categories_done_callback_.is_null()) | 238 if (pending_get_categories_done_callback_.is_null()) |
230 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); | 239 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); |
231 #endif | 240 #endif |
232 | 241 |
233 options_ = options; | 242 options_ = options; |
234 int trace_options = (options & RECORD_CONTINUOUSLY) ? | 243 int trace_options = (options & RECORD_CONTINUOUSLY) ? |
235 TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL; | 244 TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL; |
236 if (options & ENABLE_SAMPLING) { | 245 if (options & ENABLE_SAMPLING) { |
237 trace_options |= TraceLog::ENABLE_SAMPLING; | 246 trace_options |= TraceLog::ENABLE_SAMPLING; |
238 } | 247 } |
| 248 |
| 249 if (options & ENABLE_SYSTRACE) { |
239 #if defined(OS_CHROMEOS) | 250 #if defined(OS_CHROMEOS) |
240 if (options & ENABLE_SYSTRACE) { | |
241 DCHECK(!is_system_tracing_); | 251 DCHECK(!is_system_tracing_); |
242 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> | 252 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> |
243 StartSystemTracing(); | 253 StartSystemTracing(); |
244 is_system_tracing_ = true; | 254 is_system_tracing_ = true; |
| 255 #elif defined(OS_WIN) |
| 256 DCHECK(!is_system_tracing_); |
| 257 is_system_tracing_ = |
| 258 EtwSystemEventConsumer::GetInstance()->StartSystemTracing(); |
| 259 #endif |
245 } | 260 } |
246 #endif | 261 |
247 | 262 |
248 base::Closure on_enable_recording_done_callback = | 263 base::Closure on_enable_recording_done_callback = |
249 base::Bind(&TracingControllerImpl::OnEnableRecordingDone, | 264 base::Bind(&TracingControllerImpl::OnEnableRecordingDone, |
250 base::Unretained(this), | 265 base::Unretained(this), |
251 category_filter,trace_options, callback); | 266 category_filter, trace_options, callback); |
252 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 267 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
253 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, | 268 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, |
254 base::Unretained(this), | 269 base::Unretained(this), |
255 category_filter, | 270 category_filter, |
256 base::debug::TraceLog::RECORDING_MODE, | 271 base::debug::TraceLog::RECORDING_MODE, |
257 trace_options, | 272 trace_options, |
258 on_enable_recording_done_callback)); | 273 on_enable_recording_done_callback)); |
259 return true; | 274 return true; |
260 } | 275 } |
261 | 276 |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 if (!callback.is_null()) | 433 if (!callback.is_null()) |
419 callback.Run(); | 434 callback.Run(); |
420 } | 435 } |
421 | 436 |
422 void TracingControllerImpl::GetMonitoringStatus( | 437 void TracingControllerImpl::GetMonitoringStatus( |
423 bool* out_enabled, | 438 bool* out_enabled, |
424 std::string* out_category_filter, | 439 std::string* out_category_filter, |
425 TracingController::Options* out_options) { | 440 TracingController::Options* out_options) { |
426 *out_enabled = is_monitoring_; | 441 *out_enabled = is_monitoring_; |
427 *out_category_filter = | 442 *out_category_filter = |
428 TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(); | 443 TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(); |
429 *out_options = options_; | 444 *out_options = options_; |
430 } | 445 } |
431 | 446 |
432 bool TracingControllerImpl::CaptureMonitoringSnapshot( | 447 bool TracingControllerImpl::CaptureMonitoringSnapshot( |
433 const base::FilePath& result_file_path, | 448 const base::FilePath& result_file_path, |
434 const TracingFileResultCallback& callback) { | 449 const TracingFileResultCallback& callback) { |
435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
436 | 451 |
437 if (!can_disable_monitoring()) | 452 if (!can_disable_monitoring()) |
438 return false; | 453 return false; |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
661 OnDisableRecordingComplete(); | 676 OnDisableRecordingComplete(); |
662 } | 677 } |
663 | 678 |
664 void TracingControllerImpl::OnDisableRecordingComplete() { | 679 void TracingControllerImpl::OnDisableRecordingComplete() { |
665 // All acks (including from the subprocesses and the local trace) have been | 680 // All acks (including from the subprocesses and the local trace) have been |
666 // received. | 681 // received. |
667 is_recording_ = false; | 682 is_recording_ = false; |
668 | 683 |
669 #if defined(OS_CHROMEOS) | 684 #if defined(OS_CHROMEOS) |
670 if (is_system_tracing_) { | 685 if (is_system_tracing_) { |
| 686 // Disable system tracing. |
| 687 is_system_tracing_ = false; |
| 688 |
671 // Disable system tracing now that the local trace has shutdown. | 689 // Disable system tracing now that the local trace has shutdown. |
672 // This must be done last because we potentially need to push event | 690 // This must be done last because we potentially need to push event |
673 // records into the system event log for synchronizing system event | 691 // records into the system event log for synchronizing system event |
674 // timestamps with chrome event timestamps--and since the system event | 692 // timestamps with chrome event timestamps--and since the system event |
675 // log is a ring-buffer (on linux) adding them at the end is the only | 693 // log is a ring-buffer (on linux) adding them at the end is the only |
676 // way we're confident we'll have them in the final result. | 694 // way we're confident we'll have them in the final result. |
677 is_system_tracing_ = false; | |
678 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> | 695 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> |
679 RequestStopSystemTracing( | 696 RequestStopSystemTracing( |
680 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, | 697 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, |
681 base::Unretained(this))); | 698 base::Unretained(this))); |
682 return; | 699 return; |
683 } | 700 } |
| 701 #elif defined(OS_WIN) |
| 702 if (is_system_tracing_) { |
| 703 // Disable system tracing. |
| 704 is_system_tracing_ = false; |
| 705 |
| 706 |
| 707 // Stop kernel tracing and flush events. |
| 708 EtwSystemEventConsumer::GetInstance()->StopSystemTracing( |
| 709 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, |
| 710 base::Unretained(this))); |
| 711 return; |
| 712 } |
684 #endif | 713 #endif |
685 | 714 |
686 // Trigger callback if one is set. | 715 // Trigger callback if one is set. |
687 if (!pending_get_categories_done_callback_.is_null()) { | 716 if (!pending_get_categories_done_callback_.is_null()) { |
688 pending_get_categories_done_callback_.Run(known_category_groups_); | 717 pending_get_categories_done_callback_.Run(known_category_groups_); |
689 pending_get_categories_done_callback_.Reset(); | 718 pending_get_categories_done_callback_.Reset(); |
690 } else if (result_file_) { | 719 } else if (result_file_) { |
691 result_file_->Close( | 720 result_file_->Close( |
692 base::Bind(&TracingControllerImpl::OnResultFileClosed, | 721 base::Bind(&TracingControllerImpl::OnResultFileClosed, |
693 base::Unretained(this))); | 722 base::Unretained(this))); |
694 } | 723 } |
695 } | 724 } |
696 | 725 |
697 void TracingControllerImpl::OnResultFileClosed() { | 726 void TracingControllerImpl::OnResultFileClosed() { |
698 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
699 | 728 |
700 if (!result_file_) | 729 if (!result_file_) |
701 return; | 730 return; |
702 | 731 |
703 if (!pending_disable_recording_done_callback_.is_null()) { | 732 if (!pending_disable_recording_done_callback_.is_null()) { |
704 pending_disable_recording_done_callback_.Run(result_file_->path()); | 733 pending_disable_recording_done_callback_.Run(result_file_->path()); |
705 pending_disable_recording_done_callback_.Reset(); | 734 pending_disable_recording_done_callback_.Reset(); |
706 } | 735 } |
707 result_file_.reset(); | 736 result_file_.reset(); |
708 } | 737 } |
709 | 738 |
710 #if defined(OS_CHROMEOS) | 739 #if defined(OS_CHROMEOS) || defined(OS_WIN) |
711 void TracingControllerImpl::OnEndSystemTracingAcked( | 740 void TracingControllerImpl::OnEndSystemTracingAcked( |
712 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | 741 const scoped_refptr<base::RefCountedString>& events_str_ptr) { |
713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 742 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
714 | 743 |
715 if (result_file_) | 744 if (result_file_) |
716 result_file_->WriteSystemTrace(events_str_ptr); | 745 result_file_->WriteSystemTrace(events_str_ptr); |
717 | 746 |
718 DCHECK(!is_system_tracing_); | 747 DCHECK(!is_system_tracing_); |
719 OnDisableRecordingComplete(); | 748 OnDisableRecordingComplete(); |
720 } | 749 } |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
866 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 895 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
867 base::Bind(&TracingControllerImpl::OnWatchEventMatched, | 896 base::Bind(&TracingControllerImpl::OnWatchEventMatched, |
868 base::Unretained(this))); | 897 base::Unretained(this))); |
869 return; | 898 return; |
870 } | 899 } |
871 | 900 |
872 if (!watch_event_callback_.is_null()) | 901 if (!watch_event_callback_.is_null()) |
873 watch_event_callback_.Run(); | 902 watch_event_callback_.Run(); |
874 } | 903 } |
875 | 904 |
876 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) | 905 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) { |
877 { | |
878 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end()); | 906 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end()); |
879 tracing_uis_.insert(tracing_ui); | 907 tracing_uis_.insert(tracing_ui); |
880 } | 908 } |
881 | 909 |
882 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) | 910 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) { |
883 { | |
884 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui); | 911 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui); |
885 DCHECK(it != tracing_uis_.end()); | 912 DCHECK(it != tracing_uis_.end()); |
886 tracing_uis_.erase(it); | 913 tracing_uis_.erase(it); |
887 } | 914 } |
888 | 915 |
889 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) | 916 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) { |
890 { | |
891 if (is_monitoring_ == is_monitoring) | 917 if (is_monitoring_ == is_monitoring) |
892 return; | 918 return; |
893 | 919 |
894 is_monitoring_ = is_monitoring; | 920 is_monitoring_ = is_monitoring; |
895 #if !defined(OS_ANDROID) | 921 #if !defined(OS_ANDROID) |
896 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin(); | 922 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin(); |
897 it != tracing_uis_.end(); it++) { | 923 it != tracing_uis_.end(); it++) { |
898 (*it)->OnMonitoringStateChanged(is_monitoring); | 924 (*it)->OnMonitoringStateChanged(is_monitoring); |
899 } | 925 } |
900 #endif | 926 #endif |
901 } | 927 } |
902 | 928 |
903 } // namespace content | 929 } // namespace content |
OLD | NEW |