archivist_lib/
component_lifecycle.rs1use fidl::endpoints::RequestStream;
6use fidl_fuchsia_process_lifecycle::{LifecycleRequest, LifecycleRequestStream};
7use fuchsia_async as fasync;
8use fuchsia_runtime::{HandleInfo, HandleType, take_startup_handle};
9use futures::{Future, StreamExt};
10use log::{debug, warn};
11
12pub fn take_lifecycle_request_stream() -> LifecycleRequestStream {
15 let lifecycle_handle_info = HandleInfo::new(HandleType::Lifecycle, 0);
16 let lifecycle_handle = take_startup_handle(lifecycle_handle_info)
17 .expect("must have been provided a lifecycle channel in procargs");
18 let async_chan = fasync::Channel::from_channel(lifecycle_handle.into());
19 LifecycleRequestStream::from_channel(async_chan)
20}
21
22pub async fn on_stop_request<F, Fut>(mut request_stream: LifecycleRequestStream, cb: F)
25where
26 F: FnOnce() -> Fut,
27 Fut: Future<Output = ()>,
28{
29 match request_stream.next().await {
30 None => {
31 warn!("Lifecycle closed");
32 }
33 Some(Err(err)) => {
34 warn!(err:?; "Lifecycle error");
35 }
36 Some(Ok(LifecycleRequest::Stop { .. })) => {
37 debug!("Initiating shutdown.");
38 cb().await
39 }
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use fidl::endpoints::{Proxy, create_proxy_and_stream};
47 use fidl_fuchsia_process_lifecycle::LifecycleMarker;
48 use std::sync::Arc;
49 use std::sync::atomic::{AtomicBool, Ordering};
50
51 #[fuchsia::test]
52 async fn on_stop_request_invokes_callback() {
53 let (proxy, stream) = create_proxy_and_stream::<LifecycleMarker>();
54 let called = Arc::new(AtomicBool::new(false));
55 let called_clone = Arc::clone(&called);
56
57 let stop_fut = on_stop_request(stream, move || async move {
58 called_clone.store(true, Ordering::Relaxed);
59 });
60
61 proxy.stop().unwrap();
62 stop_fut.await;
63
64 assert!(called.load(Ordering::Relaxed));
65 }
66
67 #[fuchsia::test]
68 async fn on_stop_request_channel_closed() {
69 let (proxy, stream) = create_proxy_and_stream::<LifecycleMarker>();
70 let called = Arc::new(AtomicBool::new(false));
71 let called_clone = Arc::clone(&called);
72
73 let stop_fut = on_stop_request(stream, move || async move {
74 called_clone.store(true, Ordering::Relaxed);
75 });
76
77 drop(proxy);
78 stop_fut.await;
79
80 assert!(!called.load(Ordering::Relaxed));
81 }
82
83 #[fuchsia::test]
84 async fn on_stop_request_stream_error() {
85 let (proxy, stream) = create_proxy_and_stream::<LifecycleMarker>();
86 let called = Arc::new(AtomicBool::new(false));
87 let called_clone = Arc::clone(&called);
88
89 proxy.as_channel().write(&[0xff; 16], &mut []).expect("write invalid bytes");
91
92 on_stop_request(stream, move || async move {
93 called_clone.store(true, Ordering::Relaxed);
94 })
95 .await;
96
97 assert!(!called.load(Ordering::Relaxed));
98 }
99}