blob: 76af469a14e37504f7466ecd26ed9f4445f3ed34 [file] [log] [blame]
// Copyright 2023 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.
#![cfg(test)]
use attribution_testing::PrincipalIdentifier;
use fidl_fuchsia_process::HandleInfo;
use fuchsia_component_test::{
Capability, ChildOptions, RealmBuilder, RealmBuilderParams, Ref, Route,
};
use fuchsia_runtime::HandleType;
use futures_util::{FutureExt, StreamExt};
use std::sync::Arc;
use {
fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_decl as fdecl,
fidl_fuchsia_examples_colocated as fcolocated, fidl_fuchsia_memory_attribution as fattribution,
fuchsia_async as fasync,
};
#[fuchsia::test]
async fn test_attribute_memory() {
// Starts a component manager and obtain its root job, so that we can simulate
// traversing the root job of the system, the kind done in `memory_monitor`.
let builder = RealmBuilder::with_params(
RealmBuilderParams::new().from_relative_url("#meta/test_realm.cm"),
)
.await
.expect("Failed to create test realm builder");
// Add a child to receive these capabilities so that we can use them in this test.
// - fuchsia.memory.attribution.Provider
// - fuchsia.component.Realm
struct Capabilities {
attribution_provider: fattribution::ProviderProxy,
introspector: fcomponent::IntrospectorProxy,
realm: fcomponent::RealmProxy,
}
let (capabilities_sender, capabilities_receiver) = async_channel::unbounded::<Capabilities>();
let capabilities_sender = Arc::new(capabilities_sender);
let receiver = builder
.add_local_child(
"receiver",
move |handles| {
let capabilities_sender = capabilities_sender.clone();
async move {
capabilities_sender
.send(Capabilities {
attribution_provider: handles.connect_to_protocol().unwrap(),
introspector: handles.connect_to_protocol().unwrap(),
realm: handles.connect_to_protocol().unwrap(),
})
.await
.unwrap();
Ok(())
}
.boxed()
},
ChildOptions::new().eager(),
)
.await
.expect("Failed to add child");
builder
.add_route(
Route::new()
.capability(Capability::protocol_by_name("fuchsia.memory.attribution.Provider"))
.from(Ref::child("elf_runner"))
.to(&receiver),
)
.await
.unwrap();
builder
.add_route(
Route::new()
.capability(Capability::protocol_by_name("fuchsia.component.Realm"))
.from(Ref::framework())
.to(&receiver),
)
.await
.unwrap();
builder
.add_route(
Route::new()
.capability(Capability::protocol_by_name("fuchsia.component.Introspector"))
.from(Ref::framework())
.to(&receiver),
)
.await
.unwrap();
let _realm =
builder.build_in_nested_component_manager("#meta/component_manager.cm").await.unwrap();
let capabilities = capabilities_receiver.recv().await.unwrap();
// Start a colocated component.
let collection = fdecl::CollectionRef { name: "collection".to_string() };
let decl = fdecl::Child {
name: Some("colocated-component".to_string()),
url: Some("#meta/colocated-component.cm".to_string()),
startup: Some(fdecl::StartupMode::Lazy),
..Default::default()
};
let (user0, user0_peer) = zx::Channel::create();
let args = fcomponent::CreateChildArgs {
numbered_handles: Some(vec![HandleInfo {
handle: user0_peer.into(),
id: fuchsia_runtime::HandleInfo::new(HandleType::User0, 0).as_raw(),
}]),
..Default::default()
};
capabilities.realm.create_child(&collection, &decl, args).await.unwrap().unwrap();
let colocated_component_vmos =
fcolocated::ColocatedProxy::new(fasync::Channel::from_channel(user0))
.get_vmos()
.await
.unwrap();
assert!(!colocated_component_vmos.is_empty());
// Starting from the ELF runner, ask about the resource usage.
let mut mem = attribution_testing::attribute_memory(
PrincipalIdentifier(0),
"elf_runner.cm".to_owned(),
capabilities.attribution_provider,
capabilities.introspector,
);
// Stream memory attribution data until the full tree shows up.
let mut elf_runner: attribution_testing::Principal;
loop {
elf_runner = mem.next().await.unwrap();
if elf_runner.children.len() == 1 && elf_runner.children[0].children.len() == 1 {
break;
}
}
// We should get the following tree:
//
// - elf_runner.cm
// - colocated_runner.cm
// - colocated_component.cm
// - Some VMO
// - overhead
// - overhead
eprintln!("{:?}", elf_runner);
assert_eq!(elf_runner.children.len(), 1);
assert!(elf_runner.children[0].name.contains("colocated-runner"));
assert_eq!(elf_runner.children[0].children.len(), 1usize);
// Name of the colocated component
assert_eq!(&elf_runner.children[0].children[0].name, "collection:colocated-component");
let resource = &elf_runner.children[0].children[0].resources;
for vmo_koid in colocated_component_vmos {
assert!(
resource.contains(&attribution_testing::Resource::KernelObject(zx::Koid::from_raw(
vmo_koid
)))
);
}
}