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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/tracing/etw_system_event_consumer_win.h"
#include "base/base64.h"
#include "base/debug/trace_event_impl.h"
#include "base/json/json_string_value_serializer.h"
#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "content/public/browser/browser_thread.h"
namespace content {
namespace {
const int kEtwBufferSizeInKBytes = 16;
const int kEtwBufferFlushTimeoutInSeconds = 1;
std::string GuidToString(const GUID& guid) {
return base::StringPrintf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}
} // namespace
EtwSystemEventConsumer::EtwSystemEventConsumer()
: thread_("EtwConsumerThread") {
}
EtwSystemEventConsumer::~EtwSystemEventConsumer() {
}
bool EtwSystemEventConsumer::StartSystemTracing() {
// Activate kernel tracing.
if (!StartKernelSessionTracing())
return false;
// Start the consumer thread and start consuming events.
thread_.Start();
thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&EtwSystemEventConsumer::TraceAndConsumeOnThread,
base::Unretained(this)));
return true;
}
void EtwSystemEventConsumer::StopSystemTracing(const OutputCallback& callback) {
// Deactivate kernel tracing.
if (!StopKernelSessionTracing()) {
LOG(FATAL) << "Could not stop system tracing.";
}
// Stop consuming and flush events.
OutputCallback on_stop_system_tracing_done_callback =
base::Bind(&EtwSystemEventConsumer::OnStopSystemTracingDone,
base::Unretained(this),
callback);
thread_.message_loop()->PostTask(FROM_HERE,
base::Bind(&EtwSystemEventConsumer::FlushOnThread,
base::Unretained(this), on_stop_system_tracing_done_callback));
}
void EtwSystemEventConsumer::OnStopSystemTracingDone(
const OutputCallback& callback,
const scoped_refptr<base::RefCountedString>& result) {
// Stop the consumer thread.
thread_.Stop();
// Pass the serialized events.
callback.Run(result);
}
bool EtwSystemEventConsumer::StartKernelSessionTracing() {
// Enabled flags (tracing facilities).
uint32 enabled_flags = EVENT_TRACE_FLAG_IMAGE_LOAD |
EVENT_TRACE_FLAG_PROCESS |
EVENT_TRACE_FLAG_THREAD |
EVENT_TRACE_FLAG_CSWITCH;
EVENT_TRACE_PROPERTIES& p = *properties_.get();
p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
p.FlushTimer = kEtwBufferFlushTimeoutInSeconds;
p.BufferSize = kEtwBufferSizeInKBytes;
p.LogFileNameOffset = 0;
p.EnableFlags = enabled_flags;
p.Wnode.ClientContext = 1; // QPC timer accuracy.
HRESULT hr = base::win::EtwTraceController::Start(
KERNEL_LOGGER_NAME, &properties_, &session_handle_);
if (FAILED(hr)) {
VLOG(1) << "StartRealtimeSession() failed with " << hr << ".";
return false;
}
return true;
}
bool EtwSystemEventConsumer::StopKernelSessionTracing() {
HRESULT hr = base::win::EtwTraceController::Stop(
KERNEL_LOGGER_NAME, &properties_);
return SUCCEEDED(hr);
}
// static
EtwSystemEventConsumer* EtwSystemEventConsumer::GetInstance() {
return Singleton<EtwSystemEventConsumer>::get();
}
// static
void EtwSystemEventConsumer::ProcessEvent(EVENT_TRACE* event) {
EtwSystemEventConsumer::GetInstance()->AppendEventToBuffer(event);
}
void EtwSystemEventConsumer::AddSyncEventToBuffer() {
// Sync the clocks.
base::Time walltime = base::Time::NowFromSystemTime();
base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
LARGE_INTEGER walltime_in_us;
walltime_in_us.QuadPart = walltime.ToInternalValue();
LARGE_INTEGER now_in_us;
now_in_us.QuadPart = now.ToInternalValue();
// Add fields to the event.
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
value->Set("guid", new base::StringValue("ClockSync"));
value->Set("walltime", new base::StringValue(
base::StringPrintf("%08X%08X",
walltime_in_us.HighPart,
walltime_in_us.LowPart)));
value->Set("tick", new base::StringValue(
base::StringPrintf("%08X%08X",
now_in_us.HighPart,
now_in_us.LowPart)));
// Append it to the events buffer.
events_->Append(value.release());
}
void EtwSystemEventConsumer::AppendEventToBuffer(EVENT_TRACE* event) {
using base::FundamentalValue;
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
// Add header fields to the event.
LARGE_INTEGER ts_us;
ts_us.QuadPart = event->Header.TimeStamp.QuadPart / 10;
value->Set("ts", new base::StringValue(
base::StringPrintf("%08X%08X", ts_us.HighPart, ts_us.LowPart)));
value->Set("guid", new base::StringValue(GuidToString(event->Header.Guid)));
value->Set("op", new FundamentalValue(event->Header.Class.Type));
value->Set("ver", new FundamentalValue(event->Header.Class.Version));
value->Set("pid",
new FundamentalValue(static_cast<int>(event->Header.ProcessId)));
value->Set("tid",
new FundamentalValue(static_cast<int>(event->Header.ThreadId)));
value->Set("cpu", new FundamentalValue(event->BufferContext.ProcessorNumber));
// Base64 encode the payload bytes.
base::StringPiece buffer(static_cast<const char*>(event->MofData),
event->MofLength);
std::string payload;
base::Base64Encode(buffer, &payload);
value->Set("payload", new base::StringValue(payload));
// Append it to the events buffer.
events_->Append(value.release());
}
void EtwSystemEventConsumer::TraceAndConsumeOnThread() {
// Create the events buffer.
events_.reset(new base::ListValue());
// Output a clock sync event.
AddSyncEventToBuffer();
HRESULT hr = OpenRealtimeSession(KERNEL_LOGGER_NAME);
if (FAILED(hr))
return;
Consume();
Close();
}
void EtwSystemEventConsumer::FlushOnThread(const OutputCallback& callback) {
// Add the header information to the stream.
scoped_ptr<base::DictionaryValue> header(new base::DictionaryValue());
header->Set("name", new base::StringValue("ETW"));
// Release and pass the events buffer.
header->Set("content", events_.release());
// Serialize the results as a JSon string.
std::string output;
JSONStringValueSerializer serializer(&output);
serializer.Serialize(*header.get());
// Pass the result to the UI Thread.
scoped_refptr<base::RefCountedString> result =
base::RefCountedString::TakeString(&output);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(callback, result));
}
} // namespace content
|