Commit 0436dc8a authored by Michael Spang's avatar Michael Spang Committed by Commit Bot

chromecast: Add tracing agent to collect kernel traces (ftrace)

Add a tracing agent and matching service so that tracing on Cast devices
can collect kernel traces. The implementation is based on the CrOS
tracing agent and debugd service.

This is very barebones at the moment (service only depends on //base) to
keep the size down. We don't have dbus, although we might be able to use
mojo to manage the socket.

BUG=786091

Change-Id: I76157157506628004d812db3f452a486b2962845
Reviewed-on: https://chromium-review.googlesource.com/775557Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: default avatardsinclair <dsinclair@chromium.org>
Reviewed-by: default avatarLuke Halliwell <halliwell@chromium.org>
Reviewed-by: default avatarAlex Sakhartchouk <alexst@chromium.org>
Commit-Queue: Michael Spang <spang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521036}
parent 5384c653
......@@ -34,6 +34,9 @@ group("all") {
if (!is_android) {
deps += [ ":cast_shell" ]
}
if (is_linux) {
deps += [ "//chromecast/tracing" ]
}
if (chromecast_branding != "public") {
deps += [ "//chromecast/internal:all" ]
}
......@@ -514,7 +517,9 @@ foreach(locale, cast_locales) {
]
if (chromecast_branding != "public") {
sources += [ "$root_gen_dir/chromecast/internal/webui/app_strings_${locale}.pak" ]
sources += [
"$root_gen_dir/chromecast/internal/webui/app_strings_${locale}.pak",
]
deps += [ "//chromecast/internal/webui:chromecast_app_strings" ]
if (enable_chromecast_webui) {
......
# Copyright 2017 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.
import("//chromecast/chromecast.gni")
import("//testing/test.gni")
assert(!is_fuchsia)
cast_source_set("system_tracing_common") {
sources = [
"system_tracing_common.cc",
"system_tracing_common.h",
]
deps = [
"//base",
]
}
cast_executable("traced") {
sources = [
"ftrace.cc",
"ftrace.h",
"tracing_service_main.cc",
]
deps = [
":system_tracing_common",
"//base",
]
}
cast_source_set("system_tracer") {
sources = [
"system_tracer.cc",
"system_tracer.h",
]
public_deps = [
":system_tracing_common",
"//base",
]
}
group("tracing") {
deps = [
":system_tracing_common",
":traced",
]
}
spang@chromium.org
// Copyright 2017 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 "chromecast/tracing/ftrace.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "base/files/file_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/trace_event/common/trace_event_common.h"
#include "chromecast/tracing/system_tracing_common.h"
namespace chromecast {
namespace tracing {
namespace {
const char kPathTracefs[] = "/sys/kernel/tracing";
const char kTraceFileTracingOn[] = "tracing_on";
const char kTraceFileTraceMarker[] = "trace_marker";
const char kTraceFileSetEvent[] = "set_event";
const char kTraceFileTraceClock[] = "trace_clock";
const char kTraceFileTrace[] = "trace";
const char kTraceFileBufferSizeKb[] = "buffer_size_kb";
const char kBufferSizeKbRunning[] = "7040";
const char kBufferSizeKbIdle[] = "1408";
// TODO(spang): Load these lists from a configuration file.
const char* const kGfxEvents[] = {
"i915:i915_flip_request", "i915:i915_flip_complete",
"i915:i915_gem_object_pwrite", "i915:intel_gpu_freq_change",
"exynos:exynos_flip_request", "exynos:exynos_flip_complete",
"exynos:exynos_page_flip_state", "drm:drm_vblank_event",
};
const char* const kInputEvents[] = {
"irq:irq_threaded_handler_entry", "irq:irq_threaded_handler_exit",
};
const char* const kIrqEvents[] = {
"irq:irq_handler_exit", "irq:irq_handler_entry",
};
const char* const kPowerEvents[] = {
"power:cpu_idle",
"power:cpu_frequency",
"mali:mali_dvfs_set_clock",
"mali:mali_dvfs_set_voltage",
"cpufreq_interactive:cpufreq_interactive_boost",
"cpufreq_interactive:cpufreq_interactive_unboost",
"exynos_busfreq:exynos_busfreq_target_int",
"exynos_busfreq:exynos_busfreq_target_mif",
};
const char* const kSchedEvents[] = {
"sched:sched_switch", "sched:sched_wakeup",
};
const char* const kWorkqEvents[] = {
"workqueue:workqueue_execute_start", "workqueue:workqueue_execute_end",
};
void AddCategoryEvents(const std::string& category,
std::vector<std::string>* events) {
if (category == "gfx") {
std::copy(kGfxEvents, kGfxEvents + arraysize(kGfxEvents),
std::back_inserter(*events));
return;
}
if (category == "input") {
std::copy(kInputEvents, kInputEvents + arraysize(kInputEvents),
std::back_inserter(*events));
return;
}
if (category == TRACE_DISABLED_BY_DEFAULT("irq")) {
std::copy(kIrqEvents, kIrqEvents + arraysize(kIrqEvents),
std::back_inserter(*events));
return;
}
if (category == "power") {
std::copy(kPowerEvents, kPowerEvents + arraysize(kPowerEvents),
std::back_inserter(*events));
return;
}
if (category == "sched") {
std::copy(kSchedEvents, kSchedEvents + arraysize(kSchedEvents),
std::back_inserter(*events));
return;
}
if (category == "workq") {
std::copy(kWorkqEvents, kWorkqEvents + arraysize(kWorkqEvents),
std::back_inserter(*events));
return;
}
LOG(WARNING) << "Unrecognized category: " << category;
}
bool WriteTracingFile(const char* trace_file, base::StringPiece contents) {
base::FilePath path = base::FilePath(kPathTracefs).Append(trace_file);
if (!base::WriteFile(path, contents.data(), contents.size())) {
PLOG(ERROR) << "write: " << path;
return false;
}
return true;
}
bool EnableTraceEvent(base::StringPiece event) {
base::FilePath path = base::FilePath(kPathTracefs).Append(kTraceFileSetEvent);
// Enabling events returns EINVAL if the event does not exist. It is normal
// for driver specific events to be missing when the driver is not built in.
if (!base::AppendToFile(path, event.data(), event.size()) &&
errno != EINVAL) {
PLOG(ERROR) << "write: " << path;
return false;
}
return true;
}
} // namespace
bool IsValidCategory(base::StringPiece str) {
for (size_t i = 0; i < kCategoryCount; ++i) {
base::StringPiece category(kCategories[i]);
if (category == str)
return true;
}
return false;
}
bool StartFtrace(const std::vector<std::string>& categories) {
if (categories.size() == 0) {
LOG(ERROR) << "No categories to enable";
return false;
}
std::vector<std::string> events;
for (const auto& category : categories)
AddCategoryEvents(category, &events);
if (events.size() == 0) {
LOG(ERROR) << "No events to enable";
return false;
}
// Disable tracing and clear events.
if (!WriteTracingFile(kTraceFileTracingOn, "0"))
return false;
if (!WriteTracingFile(kTraceFileSetEvent, "\n"))
return false;
// Use CLOCK_MONOTONIC so that kernel timestamps align with std::steady_clock
// and base::TimeTicks.
if (!WriteTracingFile(kTraceFileTraceClock, "mono"))
return false;
for (const auto& event : events)
EnableTraceEvent(event);
if (!WriteTracingFile(kTraceFileBufferSizeKb, kBufferSizeKbRunning))
return false;
if (!WriteTracingFile(kTraceFileTracingOn, "1"))
return false;
return true;
}
bool WriteFtraceTimeSyncMarker() {
return WriteTracingFile(kTraceFileTraceMarker,
"trace_event_clock_sync: parent_ts=0");
}
bool StopFtrace() {
if (!WriteTracingFile(kTraceFileTracingOn, "0"))
return false;
return true;
}
base::ScopedFD GetFtraceData() {
base::FilePath path = base::FilePath(kPathTracefs).Append(kTraceFileTrace);
base::ScopedFD trace_data(HANDLE_EINTR(
open(path.value().c_str(), O_RDONLY | O_CLOEXEC | O_NONBLOCK)));
if (!trace_data.is_valid())
PLOG(ERROR) << "open: " << path.value();
return trace_data;
}
bool ClearFtrace() {
if (!WriteTracingFile(kTraceFileBufferSizeKb, kBufferSizeKbIdle))
return false;
if (!WriteTracingFile(kTraceFileTrace, "0"))
return false;
return true;
}
} // namespace tracing
} // namespace chromecast
// Copyright 2017 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.
#ifndef CHROMECAST_TRACING_FTRACE_H_
#define CHROMECAST_TRACING_FTRACE_H_
#include <string>
#include <vector>
#include "base/files/scoped_file.h"
#include "base/strings/string_piece.h"
namespace chromecast {
namespace tracing {
// Returns true if |category| is valid for system tracing.
bool IsValidCategory(base::StringPiece category);
// Starts ftrace for the specified categories.
//
// This must be paired with StopFtrace() or the kernel will continue tracing
// indefinitely. Returns false if an error occurs writing to tracefs - this
// usually indicates a configuration issue (e.g. tracefs not mounted).
bool StartFtrace(const std::vector<std::string>& categories);
// Writes time synchronization marker.
//
// This is used by trace-viewer to align ftrace clock with userspace
// tracing. Since CLOCK_MONOTONIC is used in both cases, this merely
// writes a zero offset. Call it at the end of tracing right before
// StopFtrace(). Returns false if an error occurs writing to tracefs.
bool WriteFtraceTimeSyncMarker();
// Stops ftrace.
//
// This is safe to call even if tracing isn't started. Returns false if an error
// occurs writing to tracefs.
bool StopFtrace();
// Opens ftrace buffer for reading.
base::ScopedFD GetFtraceData();
// Clears ftrace buffer. Returns false if an error occurs writing to tracefs.
bool ClearFtrace();
} // namespace tracing
} // namespace chromecast
#endif // CHROMECAST_TRACING_FTRACE_H_
// Copyright 2017 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 "chromecast/tracing/system_tracer.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_pump_libevent.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket.h"
#include "base/trace_event/trace_config.h"
#include "chromecast/tracing/system_tracing_common.h"
namespace chromecast {
namespace {
constexpr size_t kBufferSize = 1UL << 16;
base::ScopedFD CreateClientSocket() {
base::ScopedFD socket_fd(
socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
if (!socket_fd.is_valid()) {
PLOG(ERROR) << "socket";
return base::ScopedFD();
}
struct sockaddr_un addr =
chromecast::tracing::GetSystemTracingSocketAddress();
if (connect(socket_fd.get(), reinterpret_cast<struct sockaddr*>(&addr),
sizeof(addr))) {
PLOG(ERROR) << "connect: " << addr.sun_path;
return base::ScopedFD();
}
return socket_fd;
}
} // namespace
SystemTracer::SystemTracer() : buffer_(new char[kBufferSize]) {}
SystemTracer::~SystemTracer() {
Cleanup();
}
void SystemTracer::StartTracing(base::StringPiece categories,
StartTracingCallback callback) {
start_tracing_callback_ = std::move(callback);
if (state_ != State::INITIAL) {
FailStartTracing();
return;
}
if (categories.size() == 0) {
// No relevant categories are enabled.
FailStartTracing();
return;
}
connection_fd_ = CreateClientSocket();
if (!connection_fd_.is_valid()) {
FailStartTracing();
return;
}
if (!base::UnixDomainSocket::SendMsg(connection_fd_.get(), categories.data(),
categories.size(), std::vector<int>())) {
PLOG(ERROR) << "sendmsg";
FailStartTracing();
return;
}
connection_watcher_ = base::FileDescriptorWatcher::WatchReadable(
connection_fd_.get(),
base::BindRepeating(&SystemTracer::ReceiveStartAckAndTracePipe,
base::Unretained(this)));
state_ = State::STARTING;
}
void SystemTracer::StopTracing(const StopTracingCallback& callback) {
stop_tracing_callback_ = callback;
if (state_ != State::TRACING) {
FailStopTracing();
return;
}
char stop_tracing_message[] = {0};
if (!base::UnixDomainSocket::SendMsg(
connection_fd_.get(), stop_tracing_message,
sizeof(stop_tracing_message), std::vector<int>())) {
PLOG(ERROR) << "sendmsg";
FailStopTracing();
return;
}
trace_pipe_watcher_ = base::FileDescriptorWatcher::WatchReadable(
trace_pipe_fd_.get(), base::BindRepeating(&SystemTracer::ReceiveTraceData,
base::Unretained(this)));
state_ = State::READING;
}
void SystemTracer::ReceiveStartAckAndTracePipe() {
DCHECK_EQ(state_, State::STARTING);
std::vector<base::ScopedFD> fds;
ssize_t received = base::UnixDomainSocket::RecvMsg(
connection_fd_.get(), buffer_.get(), kBufferSize, &fds);
if (received == 0) {
LOG(ERROR) << "EOF from server";
FailStartTracing();
return;
}
if (received < 0) {
PLOG(ERROR) << "recvmsg";
FailStartTracing();
return;
}
if (fds.size() != 1) {
LOG(ERROR) << "Start ack missing trace pipe";
FailStartTracing();
return;
}
trace_pipe_fd_ = std::move(fds[0]);
connection_watcher_.reset();
state_ = State::TRACING;
std::move(start_tracing_callback_).Run(Status::OK);
}
void SystemTracer::ReceiveTraceData() {
DCHECK_EQ(state_, State::READING);
for (;;) {
ssize_t bytes =
HANDLE_EINTR(read(trace_pipe_fd_.get(), buffer_.get(), kBufferSize));
if (bytes < 0) {
if (errno == EAGAIN)
return; // Wait for more data.
PLOG(ERROR) << "read: trace";
FailStopTracing();
return;
}
if (bytes == 0) {
FinishTracing();
return;
}
trace_data_.append(buffer_.get(), bytes);
static constexpr size_t kPartialTraceDataSize = 1UL << 20; // 1 MiB
if (trace_data_.size() > kPartialTraceDataSize) {
SendPartialTraceData();
return;
}
}
}
void SystemTracer::FailStartTracing() {
std::move(start_tracing_callback_).Run(Status::FAIL);
Cleanup();
}
void SystemTracer::FailStopTracing() {
stop_tracing_callback_.Run(Status::FAIL, "");
Cleanup();
}
void SystemTracer::SendPartialTraceData() {
DCHECK_EQ(state_, State::READING);
stop_tracing_callback_.Run(Status::KEEP_GOING, std::move(trace_data_));
trace_data_ = "";
}
void SystemTracer::FinishTracing() {
DCHECK_EQ(state_, State::READING);
stop_tracing_callback_.Run(Status::OK, std::move(trace_data_));
Cleanup();
}
void SystemTracer::Cleanup() {
connection_watcher_.reset();
connection_fd_.reset();
trace_pipe_watcher_.reset();
trace_pipe_fd_.reset();
start_tracing_callback_.Reset();
stop_tracing_callback_.Reset();
state_ = State::FINISHED;
}
} // namespace chromecast
// Copyright 2017 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.
#ifndef CHROMECAST_TRACING_SYSTEM_TRACER_H_
#define CHROMECAST_TRACING_SYSTEM_TRACER_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "base/message_loop/message_pump_libevent.h"
namespace chromecast {
class SystemTracer {
public:
SystemTracer();
~SystemTracer();
enum class Status {
OK,
KEEP_GOING,
FAIL,
};
using StartTracingCallback = base::OnceCallback<void(Status)>;
using StopTracingCallback =
base::RepeatingCallback<void(Status status, std::string trace_data)>;
// Start system tracing for categories in |categories| (comma separated).
void StartTracing(base::StringPiece categories,
StartTracingCallback callback);
// Stop system tracing.
//
// This will call |callback| on the current thread with the trace data. If
// |status| is Status::KEEP_GOING, another call will be made with additional
// data.
void StopTracing(const StopTracingCallback& callback);
private:
enum class State {
INITIAL, // Not yet started.
STARTING, // Sent start message, waiting for ack.
TRACING, // Tracing, not yet requested stop.
READING, // Trace stopped, reading output.
FINISHED, // All done.
};
void ReceiveStartAckAndTracePipe();
void ReceiveTraceData();
void FailStartTracing();
void FailStopTracing();
void SendPartialTraceData();
void FinishTracing();
void Cleanup();
// Current state of tracing attempt.
State state_ = State::INITIAL;
// Unix socket connection to tracing daemon.
base::ScopedFD connection_fd_;
std::unique_ptr<base::FileDescriptorWatcher::Controller> connection_watcher_;
// Pipe for trace data.
base::ScopedFD trace_pipe_fd_;
std::unique_ptr<base::FileDescriptorWatcher::Controller> trace_pipe_watcher_;
// Read buffer (of size kBufferSize).
std::unique_ptr<char[]> buffer_;
// Callbacks for StartTracing() and StopTracing().
StartTracingCallback start_tracing_callback_;
StopTracingCallback stop_tracing_callback_;
// Trace data.
std::string trace_data_;
DISALLOW_COPY_AND_ASSIGN(SystemTracer);
};
} // namespace chromecast
#endif // CHROMECAST_TRACING_SYSTEM_TRACER_H_
// Copyright 2017 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 "chromecast/tracing/system_tracing_common.h"
#include <string.h>
#include "base/macros.h"
#include "base/trace_event/common/trace_event_common.h"
namespace chromecast {
namespace tracing {
namespace {
const char kSocketPath[] = "/dev/socket/tracing/tracing";
} // namespace
const char* const kCategories[] = {
"gfx", "input", TRACE_DISABLED_BY_DEFAULT("irq"),
"power", "sched", "workq"};
const size_t kCategoryCount = arraysize(kCategories);
sockaddr_un GetSystemTracingSocketAddress() {
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
static_assert(sizeof(kSocketPath) <= sizeof(addr.sun_path),
"Address too long");
strncpy(addr.sun_path, kSocketPath, sizeof(addr.sun_path) - 1);
addr.sun_family = AF_UNIX;
return addr;
}
} // namespace tracing
} // namespace chromecast
// Copyright 2017 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.
#ifndef CHROMECAST_TRACING_SYSTEM_TRACING_COMMON_H_
#define CHROMECAST_TRACING_SYSTEM_TRACING_COMMON_H_
#include <sys/socket.h>
#include <sys/un.h>
namespace chromecast {
namespace tracing {
extern const char* const kCategories[];
extern const size_t kCategoryCount;
sockaddr_un GetSystemTracingSocketAddress();
} // namespace tracing
} // namespace chromecast
#endif // CHROMECAST_TRACING_SYSTEM_TRACING_COMMON_H_
This diff is collapsed.
......@@ -1709,6 +1709,17 @@ jumbo_source_set("browser") {
]
}
if (is_chromecast && is_linux) {
sources += [
"tracing/cast_tracing_agent.cc",
"tracing/cast_tracing_agent.h",
]
deps += [ "//chromecast/tracing:system_tracer" ]
defines += [ "CAST_TRACING_AGENT=1" ]
}
if (is_fuchsia) {
sources += [
"child_process_launcher_helper_fuchsia.cc",
......
......@@ -7,5 +7,8 @@ include_rules = [
specific_include_rules = {
"tracing_controller_impl\.cc": [
"+v8"
],
"cast_tracing_agent\.": [
"+chromecast/tracing"
]
}
// Copyright 2017 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/cast_tracing_agent.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/task_scheduler/task_scheduler.h"
#include "base/trace_event/trace_config.h"
#include "chromecast/tracing/system_tracing_common.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/resource_coordinator/public/interfaces/service_constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace content {
namespace {
std::string GetTracingCategories(
const base::trace_event::TraceConfig& trace_config) {
std::vector<base::StringPiece> categories;
for (size_t i = 0; i < chromecast::tracing::kCategoryCount; ++i) {
base::StringPiece category(chromecast::tracing::kCategories[i]);
if (trace_config.category_filter().IsCategoryGroupEnabled(category))
categories.push_back(category);
}
return base::JoinString(categories, ",");
}
} // namespace
CastTracingAgent::CastTracingAgent(service_manager::Connector* connector)
: binding_(this) {
// Connecto to the agent registry interface.
tracing::mojom::AgentRegistryPtr agent_registry;
connector->BindInterface(resource_coordinator::mojom::kServiceName,
&agent_registry);
// Register this agent.
tracing::mojom::AgentPtr agent;
binding_.Bind(mojo::MakeRequest(&agent));
static const char kFtraceLabel[] = "systemTraceEvents";
agent_registry->RegisterAgent(std::move(agent), kFtraceLabel,
tracing::mojom::TraceDataType::STRING,
false /* supports_explicit_clock_sync */);
task_runner_ =
base::TaskScheduler::GetInstance()->CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
}
CastTracingAgent::~CastTracingAgent() = default;
// tracing::mojom::Agent. Called by Mojo internals on the UI thread.
void CastTracingAgent::StartTracing(
const std::string& config,
base::TimeTicks coordinator_time,
const Agent::StartTracingCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::trace_event::TraceConfig trace_config(config);
if (!trace_config.IsSystraceEnabled()) {
callback.Run(false /* success */);
return;
}
start_tracing_callback_ = callback;
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&CastTracingAgent::StartTracingOnIO,
base::Unretained(this),
base::ThreadTaskRunnerHandle::Get(),
GetTracingCategories(trace_config)));
}
void CastTracingAgent::StopAndFlush(tracing::mojom::RecorderPtr recorder) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
recorder_ = std::move(recorder);
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&CastTracingAgent::StopAndFlushOnIO,
base::Unretained(this),
base::ThreadTaskRunnerHandle::Get()));
}
void CastTracingAgent::RequestClockSyncMarker(
const std::string& sync_id,
const Agent::RequestClockSyncMarkerCallback& callback) {
NOTREACHED();
}
void CastTracingAgent::GetCategories(
const Agent::GetCategoriesCallback& callback) {
callback.Run("" /* categories */);
}
void CastTracingAgent::RequestBufferStatus(
const Agent::RequestBufferStatusCallback& callback) {
callback.Run(0 /* capacity */, 0 /* count */);
}
void CastTracingAgent::StartTracingOnIO(
scoped_refptr<base::TaskRunner> reply_task_runner,
const std::string& categories) {
system_tracer_ = std::make_unique<chromecast::SystemTracer>();
system_tracer_->StartTracing(
categories, base::BindOnce(&CastTracingAgent::FinishStartOnIO,
base::Unretained(this), reply_task_runner));
}
void CastTracingAgent::FinishStartOnIO(
scoped_refptr<base::TaskRunner> reply_task_runner,
chromecast::SystemTracer::Status status) {
reply_task_runner->PostTask(FROM_HERE,
base::BindOnce(&CastTracingAgent::FinishStart,
base::Unretained(this), status));
if (status != chromecast::SystemTracer::Status::OK) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&CastTracingAgent::CleanupOnIO, base::Unretained(this)));
}
}
void CastTracingAgent::FinishStart(chromecast::SystemTracer::Status status) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
start_tracing_callback_.Run(status == chromecast::SystemTracer::Status::OK);
}
void CastTracingAgent::StopAndFlushOnIO(
scoped_refptr<base::TaskRunner> reply_task_runner) {
system_tracer_->StopTracing(
base::BindRepeating(&CastTracingAgent::HandleTraceDataOnIO,
base::Unretained(this), reply_task_runner));
}
void CastTracingAgent::HandleTraceDataOnIO(
scoped_refptr<base::TaskRunner> reply_task_runner,
chromecast::SystemTracer::Status status,
std::string trace_data) {
reply_task_runner->PostTask(
FROM_HERE,
base::BindOnce(&CastTracingAgent::HandleTraceData, base::Unretained(this),
status, std::move(trace_data)));
if (status != chromecast::SystemTracer::Status::KEEP_GOING) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&CastTracingAgent::CleanupOnIO, base::Unretained(this)));
}
}
void CastTracingAgent::HandleTraceData(chromecast::SystemTracer::Status status,
std::string trace_data) {
if (recorder_ && status != chromecast::SystemTracer::Status::FAIL)
recorder_->AddChunk(std::move(trace_data));
if (status != chromecast::SystemTracer::Status::KEEP_GOING)
recorder_.reset();
}
void CastTracingAgent::CleanupOnIO() {
system_tracer_.reset();
}
} // namespace content
// Copyright 2017 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.
#ifndef CONTENT_BROWSER_TRACING_CAST_TRACING_AGENT_H_
#define CONTENT_BROWSER_TRACING_CAST_TRACING_AGENT_H_
#include <memory>
#include <string>
#include "chromecast/tracing/system_tracer.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
namespace service_manager {
class Connector;
} // namespace service_manager
namespace chromecast {
class SystemTracer;
}
namespace content {
class CastTracingAgent : public tracing::mojom::Agent {
public:
explicit CastTracingAgent(service_manager::Connector* connector);
~CastTracingAgent() override;
private:
// tracing::mojom::Agent. Called by Mojo internals on the UI thread.
void StartTracing(const std::string& config,
base::TimeTicks coordinator_time,
const Agent::StartTracingCallback& callback) override;
void StopAndFlush(tracing::mojom::RecorderPtr recorder) override;
void RequestClockSyncMarker(
const std::string& sync_id,
const Agent::RequestClockSyncMarkerCallback& callback) override;
void GetCategories(const Agent::GetCategoriesCallback& callback) override;
void RequestBufferStatus(
const Agent::RequestBufferStatusCallback& callback) override;
void StartTracingOnIO(scoped_refptr<base::TaskRunner> reply_task_runner,
const std::string& categories);
void FinishStartOnIO(scoped_refptr<base::TaskRunner> reply_task_runner,
chromecast::SystemTracer::Status status);
void FinishStart(chromecast::SystemTracer::Status status);
void StopAndFlushOnIO(scoped_refptr<base::TaskRunner> reply_task_runner);
void HandleTraceDataOnIO(scoped_refptr<base::TaskRunner> reply_task_runner,
chromecast::SystemTracer::Status,
std::string trace_data);
void HandleTraceData(chromecast::SystemTracer::Status status,
std::string trace_data);
void CleanupOnIO();
mojo::Binding<tracing::mojom::Agent> binding_;
Agent::StartTracingCallback start_tracing_callback_;
tracing::mojom::RecorderPtr recorder_;
// Task runner for collecting traces in a worker thread.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<chromecast::SystemTracer> system_tracer_;
DISALLOW_COPY_AND_ASSIGN(CastTracingAgent);
};
} // namespace content
#endif // CONTENT_BROWSER_TRACING_CAST_TRACING_AGENT_H_
......@@ -54,6 +54,10 @@
#include "content/browser/tracing/cros_tracing_agent.h"
#endif
#if defined(CAST_TRACING_AGENT)
#include "content/browser/tracing/cast_tracing_agent.h"
#endif
#if defined(OS_WIN)
#include "content/browser/tracing/etw_tracing_agent_win.h"
#endif
......@@ -139,6 +143,8 @@ void TracingControllerImpl::AddAgents() {
#if defined(OS_CHROMEOS)
agents_.push_back(std::make_unique<CrOSTracingAgent>(connector));
agents_.push_back(std::make_unique<ArcTracingAgentImpl>(connector));
#elif defined(CAST_TRACING_AGENT)
agents_.push_back(std::make_unique<CastTracingAgent>(connector));
#elif defined(OS_WIN)
agents_.push_back(std::make_unique<EtwTracingAgent>(connector));
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment