blob: d51b1bc0f2766059047e0108315aa75e72e3df12 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 "garnet/bin/ktrace_provider/log_importer.h"
#include <fuchsia/boot/c/fidl.h>
#include <lib/async/default.h>
#include <lib/fdio/directory.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace-engine/instrumentation.h>
#include <lib/zx/channel.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/log.h>
namespace ktrace_provider {
LogImporter::LogImporter() = default;
LogImporter::~LogImporter() { Stop(); }
void LogImporter::Start() {
if (log_)
return;
zx::channel local, remote;
zx_status_t status = zx::channel::create(0, &local, &remote);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to create channel";
return;
}
constexpr char kReadOnlyLogPath[] = "/svc/" fuchsia_boot_ReadOnlyLog_Name;
status = fdio_service_connect(kReadOnlyLogPath, remote.release());
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to connect to ReadOnlyLog";
return;
}
status = fuchsia_boot_ReadOnlyLogGet(local.get(), log_.reset_and_get_address());
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "ReadOnlyLogGet failed";
return;
}
start_time_ = zx_clock_get_monotonic();
time_scale_ = zx_ticks_per_second() / 1'000'000'000.0;
wait_.set_object(log_.get());
wait_.set_trigger(ZX_LOG_READABLE);
status = wait_.Begin(async_get_default_dispatcher());
FX_CHECK(status == ZX_OK) << "status=" << status;
}
void LogImporter::Stop() {
if (!log_)
return;
zx_status_t status = wait_.Cancel();
FX_CHECK(status == ZX_OK) << "status=" << status;
log_.reset();
}
void LogImporter::Handle(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
if (status != ZX_OK)
return;
alignas(zx_log_record_t) char log_buffer[ZX_LOG_RECORD_MAX];
zx_log_record_t* log_record = reinterpret_cast<zx_log_record_t*>(log_buffer);
for (;;) {
zx_status_t status = log_.read(/*options=*/0, /*buffer=*/log_record,
/*buffer_size=*/ZX_LOG_RECORD_MAX);
if (status == ZX_ERR_SHOULD_WAIT)
break;
FX_CHECK(status >= ZX_OK) << "status=" << status;
if (log_record->timestamp < start_time_)
continue;
if (auto context = trace_acquire_context()) {
trace_thread_ref_t thread_ref =
trace_make_inline_thread_ref(log_record->pid, log_record->tid);
trace_context_write_log_record(context, log_record->timestamp * time_scale_, &thread_ref,
log_record->data, log_record->datalen);
trace_release_context(context);
}
}
wait->Begin(dispatcher); // ignore errors
}
} // namespace ktrace_provider