File: etw_export_win.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (138 lines) | stat: -rw-r--r-- 4,783 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/tracing/common/etw_export_win.h"

#include <memory>

#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "base/trace_event/etw_interceptor_win.h"
#include "base/trace_event/trace_logging_minimal_win.h"
#include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
#include "third_party/perfetto/include/perfetto/tracing/tracing.h"
#include "third_party/perfetto/protos/perfetto/config/interceptor_config.gen.h"
#include "third_party/perfetto/protos/perfetto/config/track_event/track_event_config.gen.h"

namespace tracing {
namespace {

BASE_FEATURE(kEnableEtwExports,
             "EnableEtwExports",
             base::FEATURE_ENABLED_BY_DEFAULT);

// Used to protect the upper 16 bits reserved by winmeta.xml as they
// should not be used but older logging code and tools incorrectly used
// them.
constexpr uint64_t kCategoryKeywordMask = ~0xFFFF000000000000;

perfetto::TraceConfig CreateTraceConfigForETWKeyword(uint64_t keyword) {
  perfetto::TraceConfig config;
  auto* data_source = config.add_data_sources();
  auto* data_source_config = data_source->mutable_config();
  data_source_config->set_name("track_event");
  data_source_config->mutable_interceptor_config()->set_name("etwexport");
  perfetto::protos::gen::TrackEventConfig track_event_config =
      base::trace_event::ETWKeywordToTrackEventConfig(keyword);
  data_source_config->set_track_event_config_raw(
      track_event_config.SerializeAsString());
  return config;
}

class ETWExportController {
 public:
  ETWExportController();
  ~ETWExportController() = delete;

  // Called from the ETW EnableCallback when the state of the provider or
  // keywords has changed.
  void OnUpdate(TlmProvider::EventControlCode event);

 private:
  bool is_registration_complete_ = false;

  std::unique_ptr<perfetto::StartupTracingSession> tracing_session_;

  // The keywords that were enabled last time the callback was made.
  uint64_t etw_match_any_keyword_ = 0;

  // The provider is set based on channel for MSEdge, in other Chromium
  // based browsers all channels use the same GUID/provider.
  std::unique_ptr<TlmProvider> etw_provider_;
};

// This GUID is the used to identify the Chrome provider and is used whenever
// ETW is enabled via tracing tools and cannot change without updating tools
// that collect Chrome ETW data.
constexpr GUID kChromeETWGUID = {
    0xD2D578D9,
    0x2936,
    0x45B6,
    {0xA0, 0x9F, 0x30, 0xE3, 0x27, 0x15, 0xF4, 0x2D}};

ETWExportController::ETWExportController() {
  // Construct the ETW provider. If construction fails then the event logging
  // calls will fail. We're passing a callback function as part of registration.
  // This allows us to detect changes to enable/disable/keyword changes.
  etw_provider_ = std::make_unique<TlmProvider>(
      "Google.Chrome", kChromeETWGUID,
      base::BindRepeating(&ETWExportController::OnUpdate,
                          base::Unretained(this)));
  base::trace_event::ETWInterceptor::Register(etw_provider_.get());
  is_registration_complete_ = true;

  if (etw_provider_->IsEnabled()) {
    OnUpdate(TlmProvider::EventControlCode::kEnableProvider);
  }
}

void ETWExportController::OnUpdate(TlmProvider::EventControlCode event) {
  if (!is_registration_complete_) {
    return;
  }
  if (event == TlmProvider::EventControlCode::kDisableProvider) {
    if (tracing_session_) {
      tracing_session_->Abort();
      tracing_session_ = nullptr;
    }
    etw_match_any_keyword_ = 0;
    return;
  }
  if (event == TlmProvider::EventControlCode::kEnableProvider) {
    if (etw_match_any_keyword_ ==
        (etw_provider_->keyword_any() & kCategoryKeywordMask)) {
      return;
    }
    etw_match_any_keyword_ =
        etw_provider_->keyword_any() & kCategoryKeywordMask;
    if (tracing_session_) {
      tracing_session_->Abort();
      tracing_session_ = nullptr;
    }

    // ETW exporter creates a (local) startup session for the current
    // process that's never adopted and doesn't timeout. Since every
    // process enables export, an independent session is created in each
    // process.
    perfetto::Tracing::SetupStartupTracingOpts opts;
    opts.timeout_ms = 0;
    opts.backend = perfetto::kCustomBackend;

    perfetto::TraceConfig config =
        CreateTraceConfigForETWKeyword(etw_match_any_keyword_);
    tracing_session_ = perfetto::Tracing::SetupStartupTracing(config, opts);
  }
}

}  // namespace

// static
void EnableETWExport() {
  if (!base::FeatureList::IsEnabled(kEnableEtwExports)) {
    return;
  }
  static base::NoDestructor<ETWExportController> instance{};
}

}  // namespace tracing