1use crate::node_remover::NodeRemover;
6use fidl::endpoints::ControlHandle;
7use fuchsia_component::client::{connect_to_protocol, connect_to_protocol_sync};
8use fuchsia_component::server::{FidlService, ServiceFs, ServiceObjLocal};
9use futures::channel::oneshot;
10use futures::prelude::*;
11use log::{error, info, warn};
12use std::cell::RefCell;
13use std::rc::Rc;
14use {
15 fidl_fuchsia_diagnostics as fdiagnostics, fidl_fuchsia_kernel as fkernel,
16 fidl_fuchsia_process_lifecycle as flifecycle, fidl_fuchsia_system_state as fsystem_state,
17 fuchsia_async as fasync,
18};
19
20#[derive(Copy, Clone, PartialEq, Debug)]
21enum State {
22 Running,
23 PackageStopping,
24 PackageStopped,
25 BootStopping,
26 Stopped,
27}
28
29const ZX_SYSTEM_POWERCTL_REBOOT: u32 = 5;
31const ZX_SYSTEM_POWERCTL_REBOOT_BOOTLOADER: u32 = 6;
32const ZX_SYSTEM_POWERCTL_REBOOT_RECOVERY: u32 = 7;
33const ZX_SYSTEM_POWERCTL_SHUTDOWN: u32 = 8;
34const ZX_SYSTEM_POWERCTL_ACK_KERNEL_INITIATED_REBOOT: u32 = 9;
35
36struct LifecycleServer {
37 on_stop: RefCell<Option<oneshot::Sender<oneshot::Sender<zx::Status>>>>,
38}
39
40impl LifecycleServer {
41 fn new(on_stop: oneshot::Sender<oneshot::Sender<zx::Status>>) -> Self {
42 Self { on_stop: RefCell::new(Some(on_stop)) }
43 }
44
45 async fn serve(
46 self: Rc<Self>,
47 mut stream: flifecycle::LifecycleRequestStream,
48 ) -> Result<(), fidl::Error> {
49 if let Some(request) = stream.try_next().await? {
50 match request {
51 flifecycle::LifecycleRequest::Stop { control_handle } => {
52 let (tx, rx) = oneshot::channel();
53 let on_stop = self.on_stop.borrow_mut().take();
54 if let Some(on_stop) = on_stop {
55 let _ = on_stop.send(tx);
56 if let Ok(status) = rx.await {
57 control_handle.shutdown_with_epitaph(status);
58 } else {
59 control_handle.shutdown_with_epitaph(zx::Status::INTERNAL);
60 }
61 }
62 }
63 }
64 }
65 Ok(())
66 }
67}
68
69struct ShutdownManagerState {
70 state: State,
71 received_boot_shutdown_signal: bool,
72 package_shutdown_complete_callbacks: Vec<oneshot::Sender<zx::Status>>,
73 boot_shutdown_complete_callbacks: Vec<oneshot::Sender<zx::Status>>,
74 lifecycle_stop: bool,
75}
76
77pub struct ShutdownManager {
78 node_remover: Rc<dyn NodeRemover>,
79 power_resource: Option<zx::Resource>,
80 mexec_resource: Option<zx::Resource>,
81 log_flush: Option<fdiagnostics::LogFlusherProxy>,
82 internal_state: RefCell<ShutdownManagerState>,
83 scope: fasync::Scope,
84}
85
86fn get_power_resource() -> Result<zx::Resource, anyhow::Error> {
87 let client = connect_to_protocol_sync::<fkernel::PowerResourceMarker>()?;
88 let resource = client.get(zx::MonotonicInstant::INFINITE)?;
89 Ok(resource)
90}
91
92fn get_mexec_resource() -> Result<zx::Resource, anyhow::Error> {
93 let client = connect_to_protocol_sync::<fkernel::MexecResourceMarker>()?;
94 let resource = client.get(zx::MonotonicInstant::INFINITE)?;
95 Ok(resource)
96}
97
98async fn get_system_power_state() -> fsystem_state::SystemPowerState {
99 let client = match connect_to_protocol::<fsystem_state::SystemStateTransitionMarker>() {
100 Ok(c) => c,
101 Err(e) => {
102 error!("Failed to connect to StateStateTransition: {}, falling back to default", e);
103 return fsystem_state::SystemPowerState::Reboot;
104 }
105 };
106
107 match client.get_termination_system_state().await {
108 Ok(state) => state,
109 Err(e) => {
110 error!("Failed to get termination system state: {}, falling back to default", e);
111 fsystem_state::SystemPowerState::Reboot
112 }
113 }
114}
115
116impl ShutdownManager {
117 pub fn new(node_remover: Rc<dyn NodeRemover>) -> Rc<Self> {
118 let power_resource = get_power_resource()
119 .inspect_err(|e| {
120 info!("Failed to get power resource, assuming test environment: {}", e)
121 })
122 .ok();
123 let mexec_resource = get_mexec_resource()
124 .inspect_err(|e| {
125 info!("Failed to get mexec resource, assuming test environment: {}", e)
126 })
127 .ok();
128 let log_flush = connect_to_protocol::<fdiagnostics::LogFlusherMarker>()
129 .inspect_err(|e| error!("Failed to connect to LogFlusher: {}", e))
130 .ok();
131
132 let shutdown_manager = Rc::new(Self {
133 node_remover: node_remover.clone(),
134 internal_state: RefCell::new(ShutdownManagerState {
135 state: State::Running,
136 received_boot_shutdown_signal: false,
137 package_shutdown_complete_callbacks: Vec::new(),
138 boot_shutdown_complete_callbacks: Vec::new(),
139 lifecycle_stop: false,
140 }),
141 power_resource,
142 mexec_resource,
143 log_flush,
144 scope: fasync::Scope::new_with_name("shutdown_manager"),
145 });
146
147 let weak_manager = Rc::downgrade(&shutdown_manager);
148 node_remover.set_on_removal_timeout_callback(Box::new(move || {
149 if let Some(strong_manager) = weak_manager.upgrade() {
150 info!("Driver timed out during shutdown, issuing syscall to reboot/shutdown");
151 let strong_manager_clone = strong_manager.clone();
152 strong_manager.scope.spawn_local(async move {
153 strong_manager_clone.system_execute().await;
154 });
155 }
156 }));
157
158 shutdown_manager
159 }
160
161 pub fn publish<'a>(self: &Rc<Self>, fs: &mut ServiceFs<ServiceObjLocal<'a, ()>>) {
162 let self_clone = self.clone();
163 let (tx, rx) = oneshot::channel::<oneshot::Sender<zx::Status>>();
164 self.scope.spawn_local(async move {
165 if let Ok(sender) = rx.await {
166 let status = self_clone.signal_package_shutdown().await;
167 let _ = sender.send(status);
168 }
169 });
170 let devfs_with_pkg_lifecycle = Rc::new(LifecycleServer::new(tx));
171
172 let scope = self.scope.as_handle().clone();
173 fs.dir("svc").add_service_at(
174 "fuchsia.device.fs.with.pkg.lifecycle.Lifecycle",
175 FidlService::from(move |stream: flifecycle::LifecycleRequestStream| {
176 let devfs_with_pkg_lifecycle = devfs_with_pkg_lifecycle.clone();
177 scope.spawn_local(async move {
178 devfs_with_pkg_lifecycle.serve(stream).await.unwrap_or_else(|e| {
179 error!("Failed to serve devfs with pkg lifecycle: {}", e)
180 });
181 });
182 }),
183 );
184
185 let self_clone = self.clone();
186 let (tx, rx) = oneshot::channel::<oneshot::Sender<zx::Status>>();
187 self.scope.spawn_local(async move {
188 if let Ok(sender) = rx.await {
189 let status = self_clone.signal_boot_shutdown().await;
190 let _ = sender.send(status);
191 }
192 });
193 let devfs_lifecycle = Rc::new(LifecycleServer::new(tx));
194
195 let scope = self.scope.as_handle().clone();
196 fs.dir("svc").add_service_at(
197 "fuchsia.device.fs.lifecycle.Lifecycle",
198 FidlService::from(move |stream: flifecycle::LifecycleRequestStream| {
199 let devfs_lifecycle = devfs_lifecycle.clone();
200 scope.spawn_local(async move {
201 devfs_lifecycle
202 .serve(stream)
203 .await
204 .unwrap_or_else(|e| error!("Failed to serve devfs lifecycle: {}", e));
205 });
206 }),
207 );
208
209 let self_clone = self.clone();
211 let (tx, rx) = oneshot::channel::<oneshot::Sender<zx::Status>>();
212 self.scope.spawn_local(async move {
213 if let Ok(sender) = rx.await {
214 self_clone.internal_state.borrow_mut().lifecycle_stop = true;
215 let status = self_clone.signal_boot_shutdown().await;
216 let _ = sender.send(status);
217 }
218 });
219 let lifecycle_server = Rc::new(LifecycleServer::new(tx));
220
221 if let Some(handle) =
222 fuchsia_runtime::take_startup_handle(fuchsia_runtime::HandleType::Lifecycle.into())
223 {
224 let channel = zx::Channel::from(handle);
225 let server_end =
226 fidl::endpoints::ServerEnd::<flifecycle::LifecycleMarker>::new(channel);
227 let stream = server_end.into_stream();
228
229 let self_clone = self.clone();
230 self.scope.spawn_local(async move {
231 if let Err(e) = lifecycle_server.serve(stream).await {
232 error!("Lifecycle connection got unbound: {}", e);
233 let _ = self_clone.signal_boot_shutdown().await;
235 }
236 });
237 } else {
238 info!(concat!(
239 "No valid handle found for lifecycle events, assuming test environment ",
240 "and continuing"
241 ));
242 }
243 }
244
245 async fn on_package_shutdown_complete(&self) {
246 info!("Package shutdown complete");
247 let received_boot_shutdown_signal = {
248 let mut internal_state = self.internal_state.borrow_mut();
249 assert_eq!(internal_state.state, State::PackageStopping);
250 internal_state.state = State::PackageStopped;
251
252 for sender in internal_state.package_shutdown_complete_callbacks.drain(..) {
253 let _ = sender.send(zx::Status::OK);
254 }
255
256 if internal_state.received_boot_shutdown_signal {
257 internal_state.state = State::BootStopping;
258 true
259 } else {
260 false
261 }
262 };
263
264 if received_boot_shutdown_signal {
265 self.node_remover.shutdown_all_drivers().await;
266 self.on_boot_shutdown_complete().await;
267 }
268 }
269
270 async fn on_boot_shutdown_complete(&self) {
271 {
272 let mut internal_state = self.internal_state.borrow_mut();
273 assert_eq!(internal_state.state, State::BootStopping);
274 internal_state.state = State::Stopped;
275 }
276 self.system_execute().await;
277 let mut internal_state = self.internal_state.borrow_mut();
278 for sender in internal_state.boot_shutdown_complete_callbacks.drain(..) {
279 let _ = sender.send(zx::Status::OK);
280 }
281 }
282
283 async fn signal_package_shutdown(&self) -> zx::Status {
284 #![allow(clippy::await_holding_refcell_ref)]
288 let mut internal_state = self.internal_state.borrow_mut();
289
290 match internal_state.state {
291 State::Running | State::PackageStopping => {
292 let (tx, rx) = oneshot::channel();
293 internal_state.package_shutdown_complete_callbacks.push(tx);
294 if internal_state.state == State::Running {
295 internal_state.state = State::PackageStopping;
296 drop(internal_state);
297 self.node_remover.shutdown_pkg_drivers().await;
298 self.on_package_shutdown_complete().await;
299 } else {
300 drop(internal_state);
301 }
302 rx.await.unwrap_or(zx::Status::INTERNAL)
303 }
304 _ => zx::Status::OK,
305 }
306 }
307
308 async fn signal_boot_shutdown(&self) -> zx::Status {
309 #![allow(clippy::await_holding_refcell_ref)]
311 let mut internal_state = self.internal_state.borrow_mut();
312
313 if internal_state.state == State::Stopped {
314 return zx::Status::OK;
315 }
316
317 let (tx, rx) = oneshot::channel();
318 internal_state.boot_shutdown_complete_callbacks.push(tx);
319
320 internal_state.received_boot_shutdown_signal = true;
321 let state = internal_state.state;
322 match state {
323 State::Running | State::PackageStopped => {
324 internal_state.state = State::BootStopping;
325 drop(internal_state);
326
327 self.node_remover.shutdown_all_drivers().await;
328 self.on_boot_shutdown_complete().await;
329 }
330 State::BootStopping => {
331 error!("SignalBootShutdown() called during shutdown.");
332 }
333 _ => {}
334 }
335 rx.await.unwrap_or(zx::Status::INTERNAL)
336 }
337
338 async fn system_execute(&self) {
339 let shutdown_system_state = get_system_power_state().await;
340 info!("Suspend fallback with flags {:?}", shutdown_system_state);
341 let mut what = "zx_system_powerctl";
342
343 let (Some(mexec_resource), Some(power_resource)) =
344 (&self.mexec_resource, &self.power_resource)
345 else {
346 warn!("Invalid Power/mexec resources. Assuming test.");
347 let internal_state = self.internal_state.borrow();
348 if internal_state.lifecycle_stop {
349 info!("Exiting driver manager gracefully");
350 std::process::exit(0);
351 }
352 return;
353 };
354
355 info!("Flushing logs.");
356 if let Some(log_flush) = &self.log_flush
357 && let Err(e) = log_flush.wait_until_flushed().await
358 {
359 warn!("Failed to flush logs: {}", e);
360 }
361
362 info!("Executing powerctl.");
363 let status = match shutdown_system_state {
364 fsystem_state::SystemPowerState::Reboot => zx::Status::from_raw(unsafe {
365 zx::sys::zx_system_powerctl(
366 power_resource.raw_handle(),
367 ZX_SYSTEM_POWERCTL_REBOOT,
368 std::ptr::null(),
369 )
370 }),
371 fsystem_state::SystemPowerState::RebootBootloader => zx::Status::from_raw(unsafe {
372 zx::sys::zx_system_powerctl(
373 power_resource.raw_handle(),
374 ZX_SYSTEM_POWERCTL_REBOOT_BOOTLOADER,
375 std::ptr::null(),
376 )
377 }),
378 fsystem_state::SystemPowerState::RebootRecovery => zx::Status::from_raw(unsafe {
379 zx::sys::zx_system_powerctl(
380 power_resource.raw_handle(),
381 ZX_SYSTEM_POWERCTL_REBOOT_RECOVERY,
382 std::ptr::null(),
383 )
384 }),
385 fsystem_state::SystemPowerState::RebootKernelInitiated => {
386 let status = zx::Status::from_raw(unsafe {
387 zx::sys::zx_system_powerctl(
388 power_resource.raw_handle(),
389 ZX_SYSTEM_POWERCTL_ACK_KERNEL_INITIATED_REBOOT,
390 std::ptr::null(),
391 )
392 });
393 if status == zx::Status::OK {
394 loop {
396 fasync::Timer::new(std::time::Duration::from_secs(5 * 60)).await;
397 println!(
398 "driver_manager: unexpectedly still running after successful reboot syscall"
399 );
400 }
401 }
402 status
403 }
404 fsystem_state::SystemPowerState::Poweroff => zx::Status::from_raw(unsafe {
405 zx::sys::zx_system_powerctl(
406 power_resource.raw_handle(),
407 ZX_SYSTEM_POWERCTL_SHUTDOWN,
408 std::ptr::null(),
409 )
410 }),
411
412 fsystem_state::SystemPowerState::Mexec => {
413 info!("About to mexec...");
414 match mexec_boot::mexec_boot(zx::Unowned::new(mexec_resource)) {
415 Ok(()) => zx::Status::OK,
416 Err(e) => {
417 error!("mexec_boot failed: {}", e);
418 what = "zx_system_mexec";
419 zx::Status::INTERNAL
420 }
421 }
422 }
423 fsystem_state::SystemPowerState::FullyOn
424 | fsystem_state::SystemPowerState::SuspendRam => {
425 error!("Unexpected shutdown state requested: {:?}", shutdown_system_state);
426 zx::Status::INVALID_ARGS
427 }
428 };
429
430 let internal_state = self.internal_state.borrow();
431 if internal_state.lifecycle_stop {
432 info!("Exiting driver manager gracefully");
433 std::process::exit(0);
434 }
435
436 warn!("{}: {}", what, status);
437 }
438}