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