1 // Copyright 2020 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 "remoting/host/win/etw_trace_controller.h"
6 
7 #include <stdint.h>
8 #include <memory>
9 
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "remoting/host/logging.h"
13 
14 namespace remoting {
15 
16 namespace {
17 
18 constexpr wchar_t kSessionName[] = L"chrome_remote_desktop_host_logger";
19 constexpr uint8_t kDefaultTracingLevel = 4;
20 constexpr uint32_t kDefaultTracingFlags = 0;
21 constexpr size_t kDefaultBufferSizeKb = 16;
22 
23 }  // namespace
24 
25 EtwTraceController* EtwTraceController::instance_ = nullptr;
26 
27 EtwTraceController::EtwTraceController() = default;
28 
~EtwTraceController()29 EtwTraceController::~EtwTraceController() {
30   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
31   Stop();
32 }
33 
GetActiveSessionName() const34 const wchar_t* EtwTraceController::GetActiveSessionName() const {
35   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
36   return (instance_ == this) ? kSessionName : nullptr;
37 }
38 
Start()39 bool EtwTraceController::Start() {
40   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
41   DCHECK_EQ(instance_, nullptr);
42   instance_ = this;
43 
44   // The shared Chromium event tracing class registers itself as a 'classic'
45   // provider which only supports one session so stop any existing sessions now.
46   // More info on ETW provider registration:
47   // https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing#mof-classic-providers
48   base::win::EtwTraceProperties ignore;
49   HRESULT hr = base::win::EtwTraceController::Stop(kSessionName, &ignore);
50   LOG_IF(ERROR,
51          FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_WMI_INSTANCE_NOT_FOUND))
52       << "Failed to stop previous trace session: 0x" << std::hex << hr;
53 
54   hr = controller_.StartRealtimeSession(kSessionName, kDefaultBufferSizeKb);
55   if (FAILED(hr)) {
56     LOG(ERROR) << "Failed to start ETW realtime session: 0x" << std::hex << hr;
57     return false;
58   }
59 
60   hr = controller_.EnableProvider(kRemotingHostLogProviderGuid,
61                                   kDefaultTracingLevel, kDefaultTracingFlags);
62   if (FAILED(hr)) {
63     LOG(ERROR) << "Failed to configure ETW provider: 0x" << std::hex << hr;
64     controller_.Stop(nullptr);
65     return false;
66   }
67 
68   return true;
69 }
70 
Stop()71 void EtwTraceController::Stop() {
72   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
73   if (instance_ != this) {
74     DCHECK_EQ(instance_, nullptr);
75     return;
76   }
77 
78   // The following are all best effort, so try to stop tracing and clean up but
79   // don't skip any steps if a previous one failed.
80   HRESULT hr = controller_.DisableProvider(kRemotingHostLogProviderGuid);
81   LOG_IF(ERROR, FAILED(hr))
82       << "Failed to disable ETW provider: 0x" << std::hex << hr;
83 
84   hr = controller_.Flush(nullptr);
85   LOG_IF(ERROR, FAILED(hr)) << "Failed to flush events: 0x" << std::hex << hr;
86 
87   hr = controller_.Stop(nullptr);
88   LOG_IF(ERROR, FAILED(hr))
89       << "Failed to stop ETW trace session: 0x" << std::hex << hr;
90 
91   instance_ = nullptr;
92 }
93 
94 }  // namespace remoting
95