xref: /aosp_15_r20/external/cronet/base/win/event_trace_controller.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2009 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Implementation of a Windows event trace controller class.
6 
7 #include "base/win/event_trace_controller.h"
8 
9 #include "base/check.h"
10 #include "base/numerics/checked_math.h"
11 
12 constexpr size_t kDefaultRealtimeBufferSizeKb = 16;
13 
14 namespace base {
15 namespace win {
16 
EtwTraceProperties()17 EtwTraceProperties::EtwTraceProperties() {
18   memset(buffer_, 0, sizeof(buffer_));
19   EVENT_TRACE_PROPERTIES* prop = get();
20 
21   prop->Wnode.BufferSize = sizeof(buffer_);
22   prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
23   prop->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
24   prop->LogFileNameOffset =
25       sizeof(EVENT_TRACE_PROPERTIES) + sizeof(wchar_t) * kMaxStringLen;
26 }
27 
SetLoggerName(const wchar_t * logger_name)28 HRESULT EtwTraceProperties::SetLoggerName(const wchar_t* logger_name) {
29   size_t len = wcslen(logger_name) + 1;
30   if (kMaxStringLen < len)
31     return E_INVALIDARG;
32 
33   memcpy(buffer_ + get()->LoggerNameOffset, logger_name, sizeof(wchar_t) * len);
34   return S_OK;
35 }
36 
SetLoggerFileName(const wchar_t * logger_file_name)37 HRESULT EtwTraceProperties::SetLoggerFileName(const wchar_t* logger_file_name) {
38   size_t len = wcslen(logger_file_name) + 1;
39   if (kMaxStringLen < len)
40     return E_INVALIDARG;
41 
42   memcpy(buffer_ + get()->LogFileNameOffset, logger_file_name,
43          sizeof(wchar_t) * len);
44   return S_OK;
45 }
46 
47 EtwTraceController::EtwTraceController() = default;
48 
~EtwTraceController()49 EtwTraceController::~EtwTraceController() {
50   if (session_)
51     Stop(nullptr);
52 }
53 
Start(const wchar_t * session_name,EtwTraceProperties * prop)54 HRESULT EtwTraceController::Start(const wchar_t* session_name,
55                                   EtwTraceProperties* prop) {
56   DCHECK(NULL == session_ && session_name_.empty());
57   EtwTraceProperties ignore;
58   if (prop == nullptr)
59     prop = &ignore;
60 
61   HRESULT hr = Start(session_name, prop, &session_);
62   if (SUCCEEDED(hr))
63     session_name_ = session_name;
64 
65   return hr;
66 }
67 
StartFileSession(const wchar_t * session_name,const wchar_t * logfile_path,bool realtime)68 HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name,
69                                              const wchar_t* logfile_path,
70                                              bool realtime) {
71   DCHECK(NULL == session_ && session_name_.empty());
72 
73   EtwTraceProperties prop;
74   prop.SetLoggerFileName(logfile_path);
75   EVENT_TRACE_PROPERTIES& p = *prop.get();
76   p.Wnode.ClientContext = 1;                         // QPC timer accuracy.
77   p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;  // Sequential log.
78   if (realtime)
79     p.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
80 
81   p.MaximumFileSize = 100;  // 100M file size.
82   p.FlushTimer = 30;        // 30 seconds flush lag.
83   return Start(session_name, &prop);
84 }
85 
StartRealtimeSession(const wchar_t * session_name,size_t buffer_size)86 HRESULT EtwTraceController::StartRealtimeSession(const wchar_t* session_name,
87                                                  size_t buffer_size) {
88   DCHECK(NULL == session_ && session_name_.empty());
89 
90   EtwTraceProperties prop;
91   EVENT_TRACE_PROPERTIES& p = *prop.get();
92   p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY;
93   p.FlushTimer = 1;   // flush every second.
94   p.BufferSize = checked_cast<ULONG>(
95       buffer_size ? buffer_size : kDefaultRealtimeBufferSizeKb);
96   p.LogFileNameOffset = 0;
97   return Start(session_name, &prop);
98 }
99 
EnableProvider(REFGUID provider,UCHAR level,ULONG flags)100 HRESULT EtwTraceController::EnableProvider(REFGUID provider,
101                                            UCHAR level,
102                                            ULONG flags) {
103   ULONG error = ::EnableTrace(TRUE, flags, level, &provider, session_);
104   return HRESULT_FROM_WIN32(error);
105 }
106 
DisableProvider(REFGUID provider)107 HRESULT EtwTraceController::DisableProvider(REFGUID provider) {
108   ULONG error = ::EnableTrace(FALSE, 0, 0, &provider, session_);
109   return HRESULT_FROM_WIN32(error);
110 }
111 
Stop(EtwTraceProperties * properties)112 HRESULT EtwTraceController::Stop(EtwTraceProperties* properties) {
113   EtwTraceProperties ignore;
114   if (properties == nullptr)
115     properties = &ignore;
116 
117   ULONG error = ::ControlTrace(session_, nullptr, properties->get(),
118                                EVENT_TRACE_CONTROL_STOP);
119   if (ERROR_SUCCESS != error)
120     return HRESULT_FROM_WIN32(error);
121 
122   session_ = NULL;
123   session_name_.clear();
124   return S_OK;
125 }
126 
Flush(EtwTraceProperties * properties)127 HRESULT EtwTraceController::Flush(EtwTraceProperties* properties) {
128   EtwTraceProperties ignore;
129   if (properties == nullptr)
130     properties = &ignore;
131 
132   ULONG error = ::ControlTrace(session_, nullptr, properties->get(),
133                                EVENT_TRACE_CONTROL_FLUSH);
134   if (ERROR_SUCCESS != error)
135     return HRESULT_FROM_WIN32(error);
136 
137   return S_OK;
138 }
139 
Start(const wchar_t * session_name,EtwTraceProperties * properties,TRACEHANDLE * session_handle)140 HRESULT EtwTraceController::Start(const wchar_t* session_name,
141                                   EtwTraceProperties* properties,
142                                   TRACEHANDLE* session_handle) {
143   DCHECK(properties != nullptr);
144   ULONG err = ::StartTrace(session_handle, session_name, properties->get());
145   return HRESULT_FROM_WIN32(err);
146 }
147 
Query(const wchar_t * session_name,EtwTraceProperties * properties)148 HRESULT EtwTraceController::Query(const wchar_t* session_name,
149                                   EtwTraceProperties* properties) {
150   ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
151                              EVENT_TRACE_CONTROL_QUERY);
152   return HRESULT_FROM_WIN32(err);
153 }
154 
Update(const wchar_t * session_name,EtwTraceProperties * properties)155 HRESULT EtwTraceController::Update(const wchar_t* session_name,
156                                    EtwTraceProperties* properties) {
157   DCHECK(properties != nullptr);
158   ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
159                              EVENT_TRACE_CONTROL_UPDATE);
160   return HRESULT_FROM_WIN32(err);
161 }
162 
Stop(const wchar_t * session_name,EtwTraceProperties * properties)163 HRESULT EtwTraceController::Stop(const wchar_t* session_name,
164                                  EtwTraceProperties* properties) {
165   DCHECK(properties != nullptr);
166   ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
167                              EVENT_TRACE_CONTROL_STOP);
168   return HRESULT_FROM_WIN32(err);
169 }
170 
Flush(const wchar_t * session_name,EtwTraceProperties * properties)171 HRESULT EtwTraceController::Flush(const wchar_t* session_name,
172                                   EtwTraceProperties* properties) {
173   DCHECK(properties != nullptr);
174   ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
175                              EVENT_TRACE_CONTROL_FLUSH);
176   return HRESULT_FROM_WIN32(err);
177 }
178 
179 }  // namespace win
180 }  // namespace base
181