| // 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. |
| |
| use { |
| crate::{deprecated_fidl_server::*, table::*}, |
| anyhow::{format_err, Error}, |
| fuchsia_async as fasync, |
| fuchsia_component::server::ServiceFs, |
| fuchsia_inspect::{self as inspect, ArrayProperty}, |
| futures::{FutureExt, StreamExt}, |
| std::ops::AddAssign, |
| structopt::StructOpt, |
| }; |
| |
| mod deprecated_fidl_server; |
| mod table; |
| |
| struct PopulateParams<T> { |
| floor: T, |
| step: T, |
| count: usize, |
| } |
| |
| fn populated<H: inspect::HistogramProperty>(histogram: H, params: PopulateParams<H::Type>) -> H |
| where |
| H::Type: AddAssign + Copy, |
| { |
| let mut value = params.floor; |
| for _ in 0..params.count { |
| histogram.insert(value); |
| value += params.step; |
| } |
| histogram |
| } |
| |
| #[derive(Debug, StructOpt)] |
| #[structopt( |
| name = "example", |
| about = "Example component to showcase Inspect API objects, including an NxM nested table" |
| )] |
| struct Options { |
| #[structopt(long)] |
| rows: usize, |
| |
| #[structopt(long)] |
| columns: usize, |
| } |
| |
| #[fasync::run_singlethreaded] |
| async fn main() -> Result<(), Error> { |
| let opts = Options::from_args(); |
| if opts.rows == 0 || opts.columns == 0 { |
| Options::clap().print_help()?; |
| std::process::exit(1); |
| } |
| |
| let inspector = inspect::Inspector::new(); |
| let root = inspector.root(); |
| assert!(inspector.is_valid()); |
| |
| reset_unique_names(); |
| let table_node_name = unique_name("table"); |
| let example_table = |
| Table::new(opts.rows, opts.columns, &table_node_name, root.create_child(&table_node_name)); |
| |
| let int_array = root.create_int_array(unique_name("array"), 3); |
| int_array.set(0, 1); |
| int_array.add(1, 10); |
| int_array.subtract(2, 3); |
| |
| let uint_array = root.create_uint_array(unique_name("array"), 3); |
| uint_array.set(0, 1); |
| uint_array.add(1, 10); |
| uint_array.set(2, 3); |
| uint_array.subtract(2, 1); |
| |
| let double_array = root.create_double_array(unique_name("array"), 3); |
| double_array.set(0, 0.25); |
| double_array.add(1, 1.25); |
| double_array.subtract(2, 0.75); |
| |
| let _int_linear_hist = populated( |
| root.create_int_linear_histogram( |
| unique_name("histogram"), |
| inspect::LinearHistogramParams { floor: -10, step_size: 5, buckets: 3 }, |
| ), |
| PopulateParams { floor: -20, step: 1, count: 40 }, |
| ); |
| let _uint_linear_hist = populated( |
| root.create_uint_linear_histogram( |
| unique_name("histogram"), |
| inspect::LinearHistogramParams { floor: 5, step_size: 5, buckets: 3 }, |
| ), |
| PopulateParams { floor: 0, step: 1, count: 40 }, |
| ); |
| let _double_linear_hist = populated( |
| root.create_double_linear_histogram( |
| unique_name("histogram"), |
| inspect::LinearHistogramParams { floor: 0.0, step_size: 0.5, buckets: 3 }, |
| ), |
| PopulateParams { floor: -1.0, step: 0.1, count: 40 }, |
| ); |
| |
| let _int_exp_hist = populated( |
| root.create_int_exponential_histogram( |
| unique_name("histogram"), |
| inspect::ExponentialHistogramParams { |
| floor: -10, |
| initial_step: 5, |
| step_multiplier: 2, |
| buckets: 3, |
| }, |
| ), |
| PopulateParams { floor: -20, step: 1, count: 40 }, |
| ); |
| let _uint_exp_hist = populated( |
| root.create_uint_exponential_histogram( |
| unique_name("histogram"), |
| inspect::ExponentialHistogramParams { |
| floor: 0, |
| initial_step: 1, |
| step_multiplier: 2, |
| buckets: 3, |
| }, |
| ), |
| PopulateParams { floor: 0, step: 1, count: 40 }, |
| ); |
| let _double_exp_hist = populated( |
| root.create_double_exponential_histogram( |
| unique_name("histogram"), |
| inspect::ExponentialHistogramParams { |
| floor: 0.0, |
| initial_step: 1.25, |
| step_multiplier: 3.0, |
| buckets: 3, |
| }, |
| ), |
| PopulateParams { floor: -1.0, step: 0.1, count: 40 }, |
| ); |
| |
| root.record_lazy_child("lazy-node", || { |
| async move { |
| let inspector = inspect::Inspector::new(); |
| inspector.root().record_uint("uint", 3); |
| Ok(inspector) |
| } |
| .boxed() |
| }); |
| root.record_lazy_values("lazy-values", || { |
| async move { |
| let inspector = inspect::Inspector::new(); |
| inspector.root().record_double("lazy-double", 3.14); |
| Ok(inspector) |
| } |
| .boxed() |
| }); |
| |
| let mut fs = ServiceFs::new(); |
| |
| // NOTE: this FIDL service is deprecated and the following *should not* be done. |
| // Rust doesn't have a way of writing to the deprecated FIDL service, therefore |
| // we read what we wrote to the VMO and provide it through the service for testing |
| // purposes. |
| let inspector_clone = inspector.clone(); |
| fs.dir("diagnostics") |
| .add_fidl_service(move |stream| { |
| spawn_inspect_server(stream, example_table.get_node_object()); |
| }) |
| .add_fidl_service(move |stream| { |
| // Purely for test purposes. Internally inspect creates a pseudo dir diagnostics and |
| // adds it as remote in ServiceFs. However, if we try to add the VMO file and the other |
| // service in the ServiceFs, an exception occurs. This is purely a workaround for |
| // ServiceFS and for the test purpose. A regular component wouldn't do this. It would |
| // just do `inspector.serve(&mut fs);`. |
| inspect::service::spawn_tree_server( |
| inspector_clone.clone(), |
| inspect::service::TreeServerSettings::default(), |
| stream, |
| ); |
| }); |
| |
| // TODO(fxbug.dev/41952): remove when all clients writing VMO files today have been migrated to write |
| // to Tree. |
| inspector |
| .duplicate_vmo() |
| .ok_or(format_err!("Failed to duplicate VMO")) |
| .and_then(|vmo| { |
| let size = vmo.get_size()?; |
| fs.dir("diagnostics").add_vmo_file_at( |
| "root.inspect", |
| vmo, |
| 0, /* vmo offset */ |
| size, |
| ); |
| Ok(()) |
| }) |
| .unwrap_or_else(|e| { |
| eprintln!("Failed to expose vmo. Error: {:?}", e); |
| }); |
| |
| fs.take_and_serve_directory_handle()?; |
| |
| Ok(fs.collect().await) |
| } |