blob: d08fa188246751ea69dd9e45ee9c4907a5462466 [file] [log] [blame]
// Copyright 2019 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 <fidl/fuchsia.inspect/cpp/fidl.h>
#include <fidl/fuchsia.inspect/cpp/wire.h>
#include <fidl/fuchsia.kernel/cpp/wire.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/inspect/component/cpp/service.h>
#include <lib/kcounter/provider.h>
#include <lib/zx/channel.h>
#include <string.h>
#include <zircon/status.h>
#include "kcounter.h"
namespace {
/// Counter exposes kernel counter data in two ways:
/// fuchsia.kernel.Counter:
/// This protocol allows direct access to the Inspect VMO managed in the kernel
///
/// fuchsia.inspect.Tree:
/// This protocol is the standard Inspect tree server. It is how the kernel counter data
/// is exposed to tools such as `ffx inspect`.
class Counter : public fidl::WireServer<fuchsia_kernel::Counter>,
public fidl::WireServer<fuchsia_inspect::Tree> {
public:
Counter(async_dispatcher_t* dispatcher, kcounter::VmoToInspectMapper mapper)
: dispatcher_(dispatcher), mapper_(std::move(mapper)) {}
private:
void GetInspectVmo(GetInspectVmoCompleter::Sync& completer) override {
fuchsia_mem::wire::Buffer buffer;
if (zx_status_t status = mapper_.GetInspectVMO(&buffer.vmo); status != ZX_OK) {
return completer.Reply(status, {});
}
if (zx_status_t status = buffer.vmo.get_size(&buffer.size); status != ZX_OK) {
return completer.Reply(status, {});
}
completer.Reply(ZX_OK, std::move(buffer));
}
void UpdateInspectVmo(UpdateInspectVmoCompleter::Sync& completer) override {
completer.Reply(mapper_.UpdateInspectVMO());
}
/// Get the VMO handle for the Inspector handled by this server.
/// `UpdateInspectVMO` is executed on each call.
void GetContent(GetContentCompleter::Sync& completer) override {
mapper_.UpdateInspectVMO();
fidl::Arena arena;
auto content_builder = fuchsia_inspect::wire::TreeContent::Builder(arena);
fuchsia_mem::wire::Buffer buffer;
// send live VMO as the only writes that happen to this Inspector happen in `UpdateInspectVMO`
mapper_.GetInspectVMO(&buffer.vmo);
content_builder.buffer(std::move(buffer));
completer.Reply(content_builder.Build());
}
/// Not implemented. Will never be executed.
void OpenChild(OpenChildRequestView request, OpenChildCompleter::Sync& completer) override {
// This is intentionally left blank as `Counter::ListChildNames` returns a server
// handle with an empty name list. That precludes this function ever being executed.
//
// If lazy nodes are ever added to the wrapped Inspector, this and `ListChildNames` will either
// need a full implementation, or the method for exposing the Inspector will need to change.
}
/// Returns a handle to a server that will always return 0 names.
void ListChildNames(ListChildNamesRequestView request,
ListChildNamesCompleter::Sync& completer) override {
// Always return 0 names
inspect::TreeNameIterator::StartSelfManagedServer(
dispatcher_, std::move(request->tree_iterator), std::vector<std::string>{});
}
async_dispatcher_t* dispatcher_;
kcounter::VmoToInspectMapper mapper_;
};
zx_status_t Connect(void* ctx, async_dispatcher_t* dispatcher, const char* service_name,
zx_handle_t request) {
zx::channel channel{request};
if (fidl::DiscoverableProtocolName<fuchsia_kernel::Counter> == service_name) {
fidl::BindServer(dispatcher, fidl::ServerEnd<fuchsia_kernel::Counter>{std::move(channel)},
static_cast<Counter*>(ctx));
return ZX_OK;
}
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Init(void** ctx) {
auto* dispatcher = static_cast<async_dispatcher_t*>(*ctx);
auto* counter = new Counter(dispatcher, kcounter::VmoToInspectMapper{});
auto endpoints = fidl::CreateEndpoints<fuchsia_inspect::Tree>();
fidl::BindServer(dispatcher, std::move(endpoints->server), counter);
auto inspect_sink_client = component::Connect<fuchsia_inspect::InspectSink>().value();
fidl::Client client(std::move(inspect_sink_client), dispatcher);
auto result = client->Publish({{.tree = std::move(endpoints->client)}});
ZX_ASSERT(result.is_ok());
*ctx = counter;
return ZX_OK;
}
void Release(void* ctx) { delete static_cast<Counter*>(ctx); }
constexpr const char* kKcounterServices[] = {
fidl::DiscoverableProtocolName<fuchsia_kernel::Counter>,
nullptr,
};
constexpr zx_service_ops_t kKcounterOps = {
.init = Init,
.connect = Connect,
.release = Release,
};
constexpr zx_service_provider_t kcounter_service_provider = {
.version = SERVICE_PROVIDER_VERSION,
.services = kKcounterServices,
.ops = &kKcounterOps,
};
} // namespace
const zx_service_provider_t* kcounter_get_service_provider() { return &kcounter_service_provider; }