kernel_manager/
kernels.rs1use crate::{generate_kernel_name, StarnixKernel};
6use anyhow::Error;
7use fidl::endpoints::ServerEnd;
8use frunner::{ComponentControllerMarker, ComponentStartInfo};
9use fuchsia_component::client::connect_to_protocol;
10use fuchsia_sync::Mutex;
11use std::collections::HashMap;
12use std::sync::Arc;
13use vfs::execution_scope::ExecutionScope;
14use zx::AsHandleRef;
15use {
16 fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_runner as frunner,
17 fidl_fuchsia_power_system as fpower, zx,
18};
19
20const KERNEL_URL: &str = "starnix_kernel#meta/starnix_kernel.cm";
22
23fn create_lease_name(kernel_name: &str) -> String {
25 format!("starnix-kernel-{}", kernel_name)
26}
27
28pub struct Kernels {
30 kernels: Arc<Mutex<HashMap<zx::Koid, StarnixKernel>>>,
31 background_tasks: ExecutionScope,
32}
33
34impl Kernels {
35 pub fn new() -> Self {
37 let kernels = Default::default();
38 Self { kernels, background_tasks: ExecutionScope::new() }
39 }
40
41 pub async fn start(
43 &self,
44 start_info: ComponentStartInfo,
45 controller: ServerEnd<ComponentControllerMarker>,
46 ) -> Result<(), Error> {
47 let realm =
48 connect_to_protocol::<fcomponent::RealmMarker>().expect("Failed to connect to realm.");
49
50 let kernel_name = generate_kernel_name(&start_info)?;
51 let wake_lease = 'out: {
52 let Ok(activity_governor) = connect_to_protocol::<fpower::ActivityGovernorMarker>()
53 else {
54 break 'out None;
55 };
56
57 match activity_governor
58 .take_application_activity_lease(&create_lease_name(&kernel_name))
59 .await
60 {
61 Ok(l) => Some(l),
62 Err(e) => {
63 log::warn!("Failed to acquire application activity lease for kernel: {:?}", e);
64 None
65 }
66 }
67 };
68
69 let (kernel, on_stop) =
70 StarnixKernel::create(realm, KERNEL_URL, start_info, controller).await?;
71 let kernel_job = kernel.job.clone();
72 let kernel_koid = kernel.job.get_koid()?;
73
74 *kernel.wake_lease.lock() = wake_lease;
75 log::info!("Acquired wake lease for {:?}", kernel_job);
76
77 self.kernels.lock().insert(kernel_koid, kernel);
78
79 let kernels = self.kernels.clone();
80 self.background_tasks.spawn(async move {
81 on_stop.await;
82 if let Some(kernel) = kernels.lock().remove(&kernel_koid) {
83 _ = kernel.destroy().await.inspect_err(|e| log::error!("{e:?}"));
84 }
85 });
86
87 Ok(())
88 }
89
90 pub fn all_jobs(&self) -> Vec<Arc<zx::Job>> {
92 self.kernels.lock().iter().map(|(_, k)| Arc::clone(k.job())).collect()
93 }
94
95 pub fn drop_wake_lease(&self, container_job: &zx::Job) -> Result<(), Error> {
97 fuchsia_trace::instant!(
99 c"power",
100 c"starnix-runner:drop-application-activity-lease",
101 fuchsia_trace::Scope::Process
102 );
103 let job_koid = container_job.get_koid()?;
105 if let Some(kernel) = self.kernels.lock().get(&job_koid) {
106 kernel.wake_lease.lock().take();
107 log::info!("Dropped wake lease for {:?}", container_job);
108 }
109 Ok(())
110 }
111
112 pub async fn acquire_wake_lease(&self, container_job: &zx::Job) -> Result<(), Error> {
114 fuchsia_trace::duration!(c"power", c"starnix-runner:acquire-application-activity-lease");
116 let job_koid = container_job.get_koid()?;
118 if let Some(kernel) = self.kernels.lock().get(&job_koid) {
119 let activity_governor = connect_to_protocol::<fpower::ActivityGovernorMarker>()?;
120 let wake_lease = match activity_governor
121 .take_application_activity_lease(&create_lease_name(&kernel.name))
122 .await
123 {
124 Ok(l) => l,
125 Err(e) => {
126 log::warn!("Failed to acquire application activity lease for kernel: {:?}", e);
127 return Ok(());
128 }
129 };
130 *kernel.wake_lease.lock() = Some(wake_lease);
131 log::info!("Acquired wake lease for {:?}", container_job);
132 }
133 Ok(())
134 }
135}
136
137impl Drop for Kernels {
138 fn drop(&mut self) {
139 self.background_tasks.shutdown();
140 }
141}