blob: f9d61a7adbb52623a587f04657093f4d04e006d9 [file] [log] [blame]
// Copyright 2021 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.
//! `diagnostics-kcounter` component publishes kcounter Inspect VMO.
use {
anyhow::Error,
argh::FromArgs,
fidl_fuchsia_kernel::{CounterMarker, CounterProxy},
fuchsia_component::{client::connect_to_protocol, server::ServiceFs},
fuchsia_zircon as zx,
futures::prelude::*,
std::sync::Arc,
tracing::*,
};
/// The name of the subcommand and the logs-tag.
pub const PROGRAM_NAME: &str = "kcounter";
/// Command line args
#[derive(FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "kcounter")]
pub struct CommandLine {}
async fn publish_kcounter_inspect(
kcounter: CounterProxy,
inspector: &fuchsia_inspect::Inspector,
) -> Result<(), Error> {
let (state, inspect_vmo) = kcounter.get_inspect_vmo().await?;
zx::ok(state)?;
let vmo = Arc::new(inspect_vmo.vmo);
// We are adding the VMO as lazy values to root; there won't be a node called "kcounter".
inspector.root().record_lazy_values("kcounter", move || {
let kcounter_clone = kcounter.clone();
let vmo_clone = vmo.clone();
async move {
zx::ok(kcounter_clone.update_inspect_vmo().await?)?;
Ok(fuchsia_inspect::Inspector::no_op_from_vmo(vmo_clone))
}
.boxed()
});
Ok(())
}
pub async fn main() -> Result<(), Error> {
let mut fs = ServiceFs::new();
fs.take_and_serve_directory_handle()?;
let inspector = fuchsia_inspect::component::inspector();
inspect_runtime::serve(inspector, &mut fs)?;
publish_kcounter_inspect(connect_to_protocol::<CounterMarker>()?, inspector).await?;
info!("Serving");
fs.collect::<()>().await;
info!("Exiting");
Ok(())
}
#[cfg(test)]
mod tests {
use {
super::*, fidl_fuchsia_kernel::CounterRequest, fidl_fuchsia_mem::Buffer,
fuchsia_async as fasync, std::sync::Mutex,
};
#[fasync::run_until_stalled(test)]
async fn test_kcounter_proxy() -> Result<(), Error> {
let (proxy, mut stream) =
fidl::endpoints::create_proxy_and_stream::<CounterMarker>().unwrap();
let counter = Arc::new(Mutex::new((0, 0)));
let counter_in_server = counter.clone();
let _task = fasync::Task::local(async move {
while let Some(req) = stream.next().await {
let mut counter = counter_in_server.lock().unwrap();
match req {
Ok(CounterRequest::GetInspectVmo { responder }) => {
(*counter).0 += 1;
let vmo = zx::Vmo::create(0).unwrap();
responder
.send(zx::Status::OK.into_raw(), &mut Buffer { vmo, size: 0 })
.expect("Failed to respond to GetInspectVmo");
}
Ok(CounterRequest::UpdateInspectVmo { responder }) => {
(*counter).1 += 1;
responder
.send(zx::Status::OK.into_raw())
.expect("Failed to respond to UpdateInspectVmo");
}
Err(e) => {
assert!(false, "Server error: {}", e);
}
};
}
});
// Use a local Inspector instead of the static singleton so fasync won't complain about
// leaking resources.
let inspector = fuchsia_inspect::Inspector::new();
publish_kcounter_inspect(proxy, &inspector).await?;
{
let counter = counter.lock().unwrap();
assert_eq!((*counter).0, 1, "Incorrect call(s) to GetInspectVmo");
assert_eq!((*counter).1, 0, "Incorrect call(s) to UpdateInspectVmo");
};
fuchsia_inspect::reader::read(&inspector).await?;
{
let counter = counter.lock().unwrap();
assert_eq!((*counter).0, 1, "Incorrect call(s) to GetInspectVmo");
assert_eq!((*counter).1, 1, "Incorrect call(s) to UpdateInspectVmo");
};
fuchsia_inspect::reader::read(&inspector).await?;
{
let counter = counter.lock().unwrap();
assert_eq!((*counter).0, 1, "Incorrect call(s) to GetInspectVmo");
assert_eq!((*counter).1, 2, "Incorrect call(s) to UpdateInspectVmo");
};
Ok(())
}
}