15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/event_trace_provider.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cguid.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace win {
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TRACE_GUID_REGISTRATION EtwTraceProvider::obligatory_guid_registration_ = {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  &GUID_NULL,
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EtwTraceProvider::EtwTraceProvider(const GUID& provider_name)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : provider_name_(provider_name), registration_handle_(NULL),
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EtwTraceProvider::EtwTraceProvider()
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : provider_name_(GUID_NULL), registration_handle_(NULL),
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EtwTraceProvider::~EtwTraceProvider() {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Unregister();
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::EnableEvents(void* buffer) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  session_handle_ = ::GetTraceLoggerHandle(buffer);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == session_handle_) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ::GetLastError();
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enable_flags_ = ::GetTraceEnableFlags(session_handle_);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enable_level_ = ::GetTraceEnableLevel(session_handle_);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give subclasses a chance to digest the state change.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnEventsEnabled();
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ERROR_SUCCESS;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::DisableEvents() {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give subclasses a chance to digest the state change.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnEventsDisabled();
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enable_level_ = 0;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enable_flags_ = 0;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  session_handle_ = NULL;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PostEventsDisabled();
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ERROR_SUCCESS;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::Callback(WMIDPREQUESTCODE request, void* buffer) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (request) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WMI_ENABLE_EVENTS:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EnableEvents(buffer);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WMI_DISABLE_EVENTS:
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return DisableEvents();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERROR_INVALID_PARAMETER;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not reached.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG WINAPI EtwTraceProvider::ControlCallback(WMIDPREQUESTCODE request,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* context, ULONG *reserved, void* buffer) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwTraceProvider *provider = reinterpret_cast<EtwTraceProvider*>(context);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return provider->Callback(request, buffer);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::Register() {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (provider_name_ == GUID_NULL)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_INVALID_NAME;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ::RegisterTraceGuids(ControlCallback, this, &provider_name_,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1, &obligatory_guid_registration_, NULL, NULL, &registration_handle_);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::Unregister() {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a session is active, notify subclasses that it's going away.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (session_handle_ != NULL)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DisableEvents();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG ret = ::UnregisterTraceGuids(registration_handle_);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registration_handle_ = NULL;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EtwEventType type, EtwEventLevel level, const char *message) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == session_handle_ || enable_level_ < level)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_SUCCESS;  // No one listening.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwMofEvent<1> event(event_class, type, level);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.fields[0].Length = message ?
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<ULONG>(sizeof(message[0]) * (1 + strlen(message))) : 0;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ::TraceEvent(session_handle_, &event.header);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EtwEventType type, EtwEventLevel level, const wchar_t *message) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == session_handle_ || enable_level_ < level)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_SUCCESS;  // No one listening.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwMofEvent<1> event(event_class, type, level);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.fields[0].Length = message ?
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<ULONG>(sizeof(message[0]) * (1 + wcslen(message))) : 0;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ::TraceEvent(session_handle_, &event.header);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ULONG EtwTraceProvider::Log(EVENT_TRACE_HEADER* event) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enable_level_ < event->Class.Level)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_SUCCESS;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ::TraceEvent(session_handle_, event);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace win
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
135