910e62b5创建于 1月15日历史提交
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/host/win/etw_trace_controller.h"

#include <stdint.h>
#include <memory>

#include "base/check_op.h"
#include "base/logging.h"
#include "base/sequence_checker.h"
#include "remoting/base/logging.h"

namespace remoting {

namespace {

constexpr wchar_t kSessionName[] = L"chrome_remote_desktop_host_logger";
constexpr uint8_t kDefaultTracingLevel = 4;
constexpr uint32_t kDefaultTracingFlags = 0;
constexpr size_t kDefaultBufferSizeKb = 16;

}  // namespace

EtwTraceController* EtwTraceController::instance_ = nullptr;

EtwTraceController::EtwTraceController() = default;

EtwTraceController::~EtwTraceController() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  Stop();
}

const wchar_t* EtwTraceController::GetActiveSessionName() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return (instance_ == this) ? kSessionName : nullptr;
}

bool EtwTraceController::Start() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK_EQ(instance_, nullptr);
  instance_ = this;

  // The shared Chromium event tracing class registers itself as a 'classic'
  // provider which only supports one session so stop any existing sessions now.
  // More info on ETW provider registration:
  // https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing#mof-classic-providers
  base::win::EtwTraceProperties ignore;
  HRESULT hr = base::win::EtwTraceController::Stop(kSessionName, &ignore);
  LOG_IF(ERROR,
         FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_WMI_INSTANCE_NOT_FOUND))
      << "Failed to stop previous trace session: 0x" << std::hex << hr;

  hr = controller_.StartRealtimeSession(kSessionName, kDefaultBufferSizeKb);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to start ETW realtime session: 0x" << std::hex << hr;
    return false;
  }

  hr = controller_.EnableProvider(kRemotingHostLogProviderGuid,
                                  kDefaultTracingLevel, kDefaultTracingFlags);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to configure ETW provider: 0x" << std::hex << hr;
    controller_.Stop(nullptr);
    return false;
  }

  return true;
}

void EtwTraceController::Stop() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (instance_ != this) {
    DCHECK_EQ(instance_, nullptr);
    return;
  }

  // The following are all best effort, so try to stop tracing and clean up but
  // don't skip any steps if a previous one failed.
  HRESULT hr = controller_.DisableProvider(kRemotingHostLogProviderGuid);
  LOG_IF(ERROR, FAILED(hr))
      << "Failed to disable ETW provider: 0x" << std::hex << hr;

  hr = controller_.Flush(nullptr);
  LOG_IF(ERROR, FAILED(hr)) << "Failed to flush events: 0x" << std::hex << hr;

  hr = controller_.Stop(nullptr);
  LOG_IF(ERROR, FAILED(hr))
      << "Failed to stop ETW trace session: 0x" << std::hex << hr;

  instance_ = nullptr;
}

}  // namespace remoting