blob: 054b07a2a325a0508bbfc98384b456cd86c49c2e [file] [log] [blame]
// Copyright 2024 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.
use fidl::endpoints::{ClientEnd, Proxy, RequestStream, ServerEnd};
use fidl_fidl_test_components::{TriggerMarker, TriggerRequestStream};
use fuchsia_component::server::{ServiceFs, ServiceFsDir};
use fuchsia_runtime::{HandleInfo, HandleType};
use futures::{StreamExt, TryStreamExt};
use {
fidl_fuchsia_component_sandbox as fsandbox, fidl_fuchsia_process_lifecycle as flifecycle,
fuchsia_async as fasync, fuchsia_zircon as zx,
};
/// See the `stop_with_escrowed_dictionary` test case.
///
/// This program stores some state in the escrow request, to be read back the
/// next time it is started. In particular, it stores an increasing counter of
/// the number of `TriggerRequest.Run` calls.
#[fuchsia::main]
pub async fn main() {
struct Trigger(TriggerRequestStream);
// If there is no `EscrowedDictionary` processargs, initialize the counter to 0.
let counter = match fuchsia_runtime::take_startup_handle(HandleInfo::new(
HandleType::EscrowedDictionary,
0,
)) {
Some(dictionary) => {
read_counter_from_dictionary(zx::Channel::from(dictionary).into()).await
}
None => 0,
};
// Handle exactly one connection request, which is what the test sends.
let mut fs = ServiceFs::new();
let _: &mut ServiceFsDir<'_, _> = fs.dir("svc").add_fidl_service(Trigger);
let _: &mut ServiceFs<_> = fs.take_and_serve_directory_handle().unwrap();
let request = fs.next().await.unwrap();
let counter = handle_trigger(counter, request.0).await;
escrow_counter_then_stop(counter).await;
}
async fn read_counter_from_dictionary(dictionary: ClientEnd<fsandbox::DictionaryMarker>) -> u64 {
let dictionary = dictionary.into_proxy().unwrap();
let capability = dictionary.get("counter").await.unwrap().unwrap();
match capability {
fsandbox::Capability::Data(data) => match data {
fsandbox::Data::Uint64(counter) => counter,
data @ _ => panic!("unexpected {data:?}"),
},
capability @ _ => panic!("unexpected {capability:?}"),
}
}
async fn handle_trigger(mut counter: u64, stream: TriggerRequestStream) -> u64 {
let (mut stream, stalled) =
detect_stall::until_stalled(stream, fasync::Duration::from_micros(1));
while let Ok(Some(request)) = stream.try_next().await {
match request {
fidl_fidl_test_components::TriggerRequest::Run { responder } => {
counter += 1;
responder.send(&format!("{counter}")).unwrap();
}
}
}
if let Ok(Some(server_end)) = stalled.await {
// Send the server endpoint back to the framework.
fuchsia_component::client::connect_channel_to_protocol_at::<TriggerMarker>(
server_end.into(),
"/escrow",
)
.unwrap();
}
counter
}
async fn escrow_counter_then_stop(counter: u64) {
// Create a new dictionary.
let factory =
fuchsia_component::client::connect_to_protocol::<fsandbox::FactoryMarker>().unwrap();
let dictionary = factory.create_dictionary().await.unwrap();
let dictionary = dictionary.into_proxy().unwrap();
// Add the counter into the dictionary.
dictionary
.insert("counter", fsandbox::Capability::Data(fsandbox::Data::Uint64(counter)))
.await
.unwrap()
.unwrap();
// Send the dictionary away.
let lifecycle =
fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::Lifecycle, 0)).unwrap();
let lifecycle = zx::Channel::from(lifecycle);
let lifecycle = ServerEnd::<flifecycle::LifecycleMarker>::from(lifecycle);
lifecycle
.into_stream()
.unwrap()
.control_handle()
.send_on_escrow(flifecycle::LifecycleOnEscrowRequest {
escrowed_dictionary: Some(dictionary.into_channel().unwrap().into_zx_channel().into()),
..Default::default()
})
.unwrap();
}