Skip to main content

carnelian/
app.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::IdGenerator2;
6use crate::app::strategies::base::{AppStrategyPtr, create_app_strategy};
7use crate::app::strategies::framebuffer::DisplayId;
8use crate::drawing::DisplayRotation;
9use crate::geometry::Size;
10use crate::input::{DeviceId, UserInputMessage};
11use crate::message::Message;
12use crate::scene::facets::FacetId;
13use crate::view::strategies::base::ViewStrategyParams;
14use crate::view::{ViewAssistantPtr, ViewController, ViewKey};
15use anyhow::{Context as _, Error, bail, format_err};
16use fidl_fuchsia_hardware_display::{
17    ClientPriorityValue, CoordinatorListenerRequest, ProviderProxy,
18};
19use fidl_fuchsia_input_report as hid_input_report;
20use fuchsia_async::{self as fasync, DurationExt, Timer};
21use fuchsia_component::{self as component};
22use fuchsia_trace::duration;
23
24use futures::StreamExt;
25use futures::channel::mpsc::{UnboundedSender, unbounded};
26use futures::future::{Either, Future};
27use serde::Deserialize;
28use std::any::Any;
29use std::collections::BTreeMap;
30use std::fmt::Debug;
31use std::fs;
32use std::path::PathBuf;
33use std::pin::{Pin, pin};
34use std::sync::OnceLock;
35
36pub(crate) mod strategies;
37
38/// Type alias for a non-sync future
39pub type LocalBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
40
41const fn keyboard_autorepeat_default() -> bool {
42    true
43}
44
45fn duration_from_millis(time_in_millis: u64) -> Result<std::time::Duration, Error> {
46    Ok(std::time::Duration::from_millis(time_in_millis))
47}
48
49fn deserialize_millis<'de, D>(deserializer: D) -> Result<std::time::Duration, D::Error>
50where
51    D: serde::Deserializer<'de>,
52{
53    let ms = u64::deserialize(deserializer)?;
54    duration_from_millis(ms).map_err(serde::de::Error::custom)
55}
56
57const fn keyboard_autorepeat_slow_interval_default() -> std::time::Duration {
58    const KEYBOARD_AUTOREPEAT_SLOW_INTERVAL: std::time::Duration =
59        std::time::Duration::from_millis(250);
60    KEYBOARD_AUTOREPEAT_SLOW_INTERVAL
61}
62
63const fn keyboard_autorepeat_fast_interval_default() -> std::time::Duration {
64    const KEYBOARD_AUTOREPEAT_FAST_INTERVAL: std::time::Duration =
65        std::time::Duration::from_millis(50);
66    KEYBOARD_AUTOREPEAT_FAST_INTERVAL
67}
68
69const fn display_resource_release_delay_default() -> std::time::Duration {
70    const DISPLAY_RESOURCE_RELEASE_DELAY_DEFAULT: std::time::Duration =
71        std::time::Duration::from_secs(5);
72    DISPLAY_RESOURCE_RELEASE_DELAY_DEFAULT
73}
74
75const fn startup_delay_default() -> std::time::Duration {
76    const STARTUP_DELAY_DEFAULT: std::time::Duration = std::time::Duration::from_secs(0);
77    STARTUP_DELAY_DEFAULT
78}
79
80/// Enum used by Config to control what sort of views
81/// will be used.
82#[derive(Debug, Deserialize)]
83#[serde(rename_all = "lowercase")]
84pub enum ViewMode {
85    /// Choose automatically based on the environment
86    Auto,
87    /// Only create views hosted by Scenic.
88    Hosted,
89    /// Only create views directly running directly on the display coordinator.
90    Direct,
91}
92
93impl Default for ViewMode {
94    fn default() -> Self {
95        Self::Auto
96    }
97}
98
99/// Grab-bag of configuration options for Carnelian apps.
100#[derive(Debug, Deserialize)]
101pub struct Config {
102    #[serde(default = "keyboard_autorepeat_default")]
103    /// Whether, when running without Scenic, this application should
104    /// receive keyboard repeat events.
105    pub keyboard_autorepeat: bool,
106    #[serde(
107        default = "keyboard_autorepeat_slow_interval_default",
108        deserialize_with = "deserialize_millis"
109    )]
110    /// The initial and maximum interval between keyboard repeat events, in
111    /// milliseconds, when running without Scenic.
112    pub keyboard_autorepeat_slow_interval: std::time::Duration,
113    #[serde(
114        default = "keyboard_autorepeat_fast_interval_default",
115        deserialize_with = "deserialize_millis"
116    )]
117    /// The minimum interval between keyboard repeat events, in
118    /// milliseconds, when running without Scenic.
119    pub keyboard_autorepeat_fast_interval: std::time::Duration,
120    #[serde(default)]
121    /// Whether to try to use hardware rendering (Spinel).
122    pub use_spinel: bool,
123    /// Client priority when connecting to the display coordinator. If not set,
124    /// the client will use the priority value for primary clients.
125    #[serde(default)]
126    pub client_priority: Option<ClientPriorityValue>,
127    /// What sort of view system to use.
128    #[serde(default)]
129    pub view_mode: ViewMode,
130    #[serde(default)]
131    /// Application option to exercise transparent rotation.
132    pub display_rotation: DisplayRotation,
133    #[serde(default)]
134    /// Application option to select keymap. If named keymap is not found
135    /// the fallback is US QWERTY.
136    pub keymap_name: Option<String>,
137    #[serde(
138        default = "display_resource_release_delay_default",
139        deserialize_with = "deserialize_millis"
140    )]
141    /// How long should carnelian wait before releasing display resources when
142    /// it loses ownership of the display while running directly on the display. The default
143    /// value is five seconds, so that the resource will not be rapidly allocated
144    /// and deallocated when switching quickly between virtcon and the regular display.
145    pub display_resource_release_delay: std::time::Duration,
146    #[serde(default)]
147    /// In a bringup build the display coordinator might not support multiple
148    /// buffers so Carnelian might have to run with only a
149    /// single buffer. This configuration option is to allow testing rendering
150    /// with a single buffer even in build that supports multiple.
151    pub buffer_count: Option<usize>,
152    #[serde(default)]
153    /// Whether input events are needed.
154    pub input: bool,
155    #[serde(default)]
156    /// Whether output can be translucent and needs blending.
157    pub needs_blending: bool,
158    #[serde(default = "startup_delay_default", deserialize_with = "deserialize_millis")]
159    /// How long to wait before entering event loop.
160    pub startup_delay: std::time::Duration,
161}
162
163impl Config {
164    pub(crate) fn get() -> &'static Config {
165        // Some input tests access the config. Rather than requiring setup everywhere,
166        // default the config values for testing purposes.
167        CONFIG.get_or_init(|| Config::default())
168    }
169}
170
171impl Default for Config {
172    fn default() -> Self {
173        Self {
174            keyboard_autorepeat: keyboard_autorepeat_default(),
175            keyboard_autorepeat_slow_interval: keyboard_autorepeat_slow_interval_default(),
176            keyboard_autorepeat_fast_interval: keyboard_autorepeat_fast_interval_default(),
177            use_spinel: false,
178            client_priority: None,
179            view_mode: ViewMode::default(),
180            display_rotation: DisplayRotation::Deg0,
181            keymap_name: None,
182            display_resource_release_delay: display_resource_release_delay_default(),
183            buffer_count: None,
184            input: true,
185            needs_blending: false,
186            startup_delay: Default::default(),
187        }
188    }
189}
190
191pub(crate) static CONFIG: OnceLock<Config> = OnceLock::new();
192
193pub(crate) type InternalSender = UnboundedSender<MessageInternal>;
194
195/// Target of a Any-based message
196#[derive(Debug, Clone, Copy)]
197pub enum MessageTarget {
198    /// target a facet in a view
199    Facet(ViewKey, FacetId),
200    /// target the view assistant in a view.
201    View(ViewKey),
202    /// targe the application assistant.
203    Application,
204}
205
206/// Options when creating a view.
207pub type CreateViewOptions = Box<dyn Any>;
208
209/// Context struct passed to the application assistant creator
210// function.
211#[derive(Clone)]
212pub struct AppSender {
213    sender: InternalSender,
214}
215
216impl AppSender {
217    /// Send a message to a view controller.
218    pub fn queue_message(&self, target: MessageTarget, message: Message) {
219        self.sender
220            .unbounded_send(MessageInternal::TargetedMessage(target, message))
221            .expect("AppSender::queue_message - unbounded_send");
222    }
223
224    /// Request that a frame be rendered at the next appropriate time.
225    pub fn request_render(&self, target: ViewKey) {
226        self.sender
227            .unbounded_send(MessageInternal::RequestRender(target))
228            .expect("AppSender::request_render - unbounded_send");
229    }
230
231    /// Request the creation of an additional view.
232    pub fn create_additional_view(&self, options: Option<CreateViewOptions>) -> ViewKey {
233        let view_key = IdGenerator2::<ViewKey>::next().expect("view_key");
234        self.sender
235            .unbounded_send(MessageInternal::CreateAdditionalView(view_key, options))
236            .expect("AppSender::create_additional_view - unbounded_send");
237        view_key
238    }
239
240    /// Close an additional view. It is a fatal error to attempt to close a view that
241    /// was not created with `create_additional_view()`.
242    pub fn close_additional_view(&self, view_key: ViewKey) {
243        self.sender
244            .unbounded_send(MessageInternal::CloseAdditionalView(view_key))
245            .expect("AppSender::close_additional_view - unbounded_send");
246    }
247
248    /// Create an futures mpsc sender and a task to poll the receiver and
249    /// forward the message to the app sender. This setup works around the problem
250    /// that dyn Any references cannot be `Send` at the cost of an extra trip through
251    /// the executor.
252    /// The 'static trait bounds here means that messages send across thread may not
253    /// contain any non-static references. The data in the messages must be owned, but
254    /// no not themselves need to be static.
255    pub fn create_cross_thread_sender<T: 'static + Send>(
256        &self,
257        target: MessageTarget,
258    ) -> UnboundedSender<T> {
259        let (sender, mut receiver) = unbounded::<T>();
260        let app_sender = self.sender.clone();
261        let f = async move {
262            while let Some(message) = receiver.next().await {
263                app_sender
264                    .unbounded_send(MessageInternal::TargetedMessage(target, Box::new(message)))
265                    .expect("unbounded_send");
266            }
267        };
268        // This task can be detached as it will exit when the unbounded sender
269        // it provides is dropped.
270        fasync::Task::local(f).detach();
271        sender
272    }
273
274    /// Create an context for testing things that need an app context.
275    pub fn new_for_testing_purposes_only() -> AppSender {
276        let (internal_sender, _) = unbounded::<MessageInternal>();
277        AppSender { sender: internal_sender }
278    }
279}
280
281fn make_app_assistant_fut<T: AppAssistant + Default + 'static>(
282    _: &AppSender,
283) -> LocalBoxFuture<'_, Result<AppAssistantPtr, Error>> {
284    let f = async move {
285        let assistant = Box::new(T::default());
286        Ok::<AppAssistantPtr, Error>(assistant)
287    };
288    Box::pin(f)
289}
290
291/// Convenience function to create an application assistant that implements Default.
292pub fn make_app_assistant<T: AppAssistant + Default + 'static>() -> AssistantCreatorFunc {
293    Box::new(make_app_assistant_fut::<T>)
294}
295
296/// Parameter struction for view creation
297pub struct ViewCreationParameters {
298    /// ViewKey for the new view.
299    pub view_key: ViewKey,
300    /// App sender that might be of use to the new view assistant.
301    pub app_sender: AppSender,
302    /// Display ID of the hosting display for views running directly
303    /// on the display coordinator.
304    pub display_id: Option<DisplayId>,
305    /// Options passed to `create_additional_view()`, if this view is being created
306    /// by that function and if the caller passed any.
307    pub options: Option<Box<dyn Any>>,
308}
309
310impl Debug for ViewCreationParameters {
311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312        f.debug_struct("ViewCreationParameters")
313            .field("view_key", &self.view_key)
314            .field("display_id", &self.display_id)
315            .field("options", &self.options)
316            .finish()
317    }
318}
319
320/// Trait that a mod author must implement. Currently responsible for creating
321/// a view assistant when the Fuchsia view framework requests that the mod create
322/// a view.
323pub trait AppAssistant {
324    /// This method is responsible for setting up the AppAssistant implementation.
325    /// _It's not clear if this is going to so useful, as anything that isn't
326    /// initialized in the creation of the structure implementing AppAssistant
327    /// is going to have to be represented as an `Option`, which is awkward._
328    fn setup(&mut self) -> Result<(), Error>;
329
330    /// Called when the Fuchsia view system requests that a view be created, or once at startup
331    /// when running without Scenic.
332    fn create_view_assistant(&mut self, _: ViewKey) -> Result<ViewAssistantPtr, Error> {
333        todo!("Must implement create_view_assistant_with_parameters or create_view_assistant");
334    }
335
336    /// Called when the Fuchsia view system requests that a view be created. Provides
337    /// parameters to view creation that include anything provided the the view creation
338    /// requestor and an AppSender.
339    fn create_view_assistant_with_parameters(
340        &mut self,
341        params: ViewCreationParameters,
342    ) -> Result<ViewAssistantPtr, Error> {
343        self.create_view_assistant(params.view_key)
344    }
345
346    /// Return the list of names of services this app wants to provide
347    fn outgoing_services_names(&self) -> Vec<&'static str> {
348        Vec::new()
349    }
350
351    /// Handle a request to connect to a service provided by this app
352    fn handle_service_connection_request(
353        &mut self,
354        _service_name: &str,
355        _channel: fasync::Channel,
356    ) -> Result<(), Error> {
357        return Err(format_err!("handle_service_connection_request not implemented"));
358    }
359
360    /// Filter Carnelian configuration at runtime, if needed.
361    fn filter_config(&mut self, _config: &mut Config) {}
362
363    /// This method is called when `App::queue_message` is called with `Application`
364    /// as target.
365    #[allow(unused_variables)]
366    fn handle_message(&mut self, message: Message) {}
367}
368
369/// Reference to an application assistant.
370pub type AppAssistantPtr = Box<dyn AppAssistant>;
371
372/// Struct that implements module-wide responsibilities, currently limited
373/// to creating views on request.
374pub struct App {
375    strategy: AppStrategyPtr,
376    view_controllers: BTreeMap<ViewKey, ViewController>,
377    assistant: AppAssistantPtr,
378    messages: Vec<(ViewKey, Message)>,
379    sender: InternalSender,
380    _inspect_server: Option<inspect_runtime::PublishedInspectController>,
381}
382
383#[derive(Debug)]
384pub(crate) enum MessageInternal {
385    ServiceConnection(zx::Channel, &'static str),
386    CreateView(ViewStrategyParams),
387    CreateAdditionalView(ViewKey, Option<CreateViewOptions>),
388    CloseAdditionalView(ViewKey),
389    MetricsChanged(ViewKey, Size),
390    SizeChanged(ViewKey, Size),
391    Focus(ViewKey, bool),
392    CloseViewsOnDisplay(DisplayId),
393    RequestRender(ViewKey),
394    Render(ViewKey),
395    ImageFreed(ViewKey, u64, u32),
396    TargetedMessage(MessageTarget, Message),
397    RegisterDevice(DeviceId, hid_input_report::DeviceDescriptor),
398    InputReport(DeviceId, hid_input_report::InputReport),
399    KeyboardAutoRepeat(DeviceId),
400    OwnershipChanged(bool),
401    DropDisplayResources,
402    FlatlandOnNextFrameBegin(ViewKey, fidl_fuchsia_ui_composition::OnNextFrameBeginValues),
403    FlatlandOnFramePresented(ViewKey, fidl_fuchsia_scenic_scheduling::FramePresentedInfo),
404    FlatlandOnError(ViewKey, fuchsia_scenic::flatland::FlatlandError),
405    NewDisplayCoordinator(ProviderProxy),
406    DisplayCoordinatorListenerRequest(CoordinatorListenerRequest),
407
408    UserInputMessage(ViewKey, UserInputMessage),
409}
410
411/// Future that returns an application assistant.
412pub type AssistantCreator<'a> = LocalBoxFuture<'a, Result<AppAssistantPtr, Error>>;
413/// Function that creates an AssistantCreator future.
414pub type AssistantCreatorFunc = Box<dyn FnOnce(&AppSender) -> AssistantCreator<'_>>;
415
416impl App {
417    fn new(sender: InternalSender, strategy: AppStrategyPtr, assistant: AppAssistantPtr) -> App {
418        App {
419            strategy,
420            view_controllers: BTreeMap::new(),
421            assistant,
422            messages: Vec::new(),
423            sender,
424            _inspect_server: inspect_runtime::publish(
425                fuchsia_inspect::component::inspector(),
426                inspect_runtime::PublishOptions::default(),
427            ),
428        }
429    }
430
431    fn load_and_filter_config(assistant: &mut AppAssistantPtr) -> Result<(), Error> {
432        let mut config = Self::load_config()?;
433        assistant.filter_config(&mut config);
434        CONFIG.set(config).expect("config set");
435        Ok(())
436    }
437
438    /// Starts an application based on Carnelian. The `assistant` parameter will
439    /// be used to create new views when asked to do so by the Fuchsia view system.
440    pub fn run(assistant_creator_func: AssistantCreatorFunc) -> Result<(), Error> {
441        let mut executor = fasync::LocalExecutor::default();
442        let (internal_sender, mut internal_receiver) = unbounded::<MessageInternal>();
443        let f = async {
444            let app_sender = AppSender { sender: internal_sender.clone() };
445            let assistant_creator = assistant_creator_func(&app_sender);
446            let mut assistant = assistant_creator.await?;
447            Self::load_and_filter_config(&mut assistant)?;
448            let strat = create_app_strategy(&internal_sender).await?;
449            let mut app = App::new(internal_sender, strat, assistant);
450            app.app_init_common().await?;
451            let startup_delay = Config::get().startup_delay;
452            if !startup_delay.is_zero() {
453                duration!("gfx", "App::run-startup-delay");
454                std::thread::sleep(Config::get().startup_delay);
455            }
456            while let Some(message) = internal_receiver.next().await {
457                app.handle_message(message).await?;
458            }
459            Ok::<(), Error>(())
460        };
461        executor.run_singlethreaded(f)?;
462        Ok(())
463    }
464
465    async fn handle_message(&mut self, message: MessageInternal) -> Result<(), Error> {
466        match message {
467            MessageInternal::ServiceConnection(channel, service_name) => {
468                let channel = fasync::Channel::from_channel(channel);
469                self.assistant
470                    .handle_service_connection_request(service_name, channel)
471                    .unwrap_or_else(|e| {
472                        eprintln!("error running {} server: {:?}", service_name, e)
473                    });
474            }
475            MessageInternal::CreateView(params) => {
476                self.create_view_with_params(params, None).await?
477            }
478            MessageInternal::CreateAdditionalView(view_key, options) => {
479                self.create_additional_view(view_key, options).await?
480            }
481            MessageInternal::CloseAdditionalView(view_key) => {
482                self.close_additional_view(view_key)?;
483            }
484            MessageInternal::MetricsChanged(view_id, metrics) => {
485                if let Ok(view) = self.get_view(view_id) {
486                    view.handle_metrics_changed(metrics);
487                }
488            }
489            MessageInternal::SizeChanged(view_id, new_size) => {
490                if let Ok(view) = self.get_view(view_id) {
491                    view.handle_size_changed(new_size);
492                }
493            }
494            MessageInternal::Focus(view_id, focused) => {
495                if let Ok(view) = self.get_view(view_id) {
496                    view.focus(focused);
497                }
498            }
499            MessageInternal::RequestRender(view_id) => {
500                if let Ok(view) = self.get_view(view_id) {
501                    view.request_render();
502                }
503            }
504            MessageInternal::Render(view_id) => {
505                if let Ok(view) = self.get_view(view_id) {
506                    view.render().await;
507                }
508            }
509            MessageInternal::CloseViewsOnDisplay(display_id) => {
510                let view_keys = self.get_view_keys_for_display(display_id);
511                for view_key in view_keys.into_iter() {
512                    self.close_view(view_key);
513                }
514            }
515            MessageInternal::ImageFreed(view_id, image_id, collection_id) => {
516                self.image_freed(view_id, image_id, collection_id)
517            }
518            MessageInternal::TargetedMessage(target, message) => match target {
519                MessageTarget::Facet(view_id, facet_id) => {
520                    let view = self.get_view(view_id).context("TargetedMessage")?;
521                    view.send_facet_message(facet_id, message).context("TargetedMessage")?;
522                }
523                MessageTarget::View(view_id) => {
524                    let view = self.get_view(view_id).context("TargetedMessage")?;
525                    view.send_message(message);
526                }
527                MessageTarget::Application => {
528                    self.assistant.handle_message(message);
529                }
530            },
531            MessageInternal::RegisterDevice(device_id, device_descriptor) => {
532                self.strategy.handle_register_input_device(&device_id, &device_descriptor);
533            }
534            MessageInternal::InputReport(device_id, input_report) => {
535                let input_events = self.strategy.handle_input_report(&device_id, &input_report);
536                if let Some(focused_view_key) = self.get_focused_view_key() {
537                    let view = self.get_view(focused_view_key).context("InputReport")?;
538                    view.handle_input_events(input_events).context("InputReport")?;
539                } else {
540                    eprintln!("dropping input report due to no focused view");
541                }
542            }
543            MessageInternal::KeyboardAutoRepeat(device_id) => {
544                let input_events = self.strategy.handle_keyboard_autorepeat(&device_id);
545                if let Some(focused_view_key) = self.get_focused_view_key() {
546                    let view = self.get_view(focused_view_key).context("KeyboardAutoRepeat")?;
547                    view.handle_input_events(input_events).context("KeyboardAutoRepeat")?;
548                } else {
549                    eprintln!("dropping keyboard auto repeat due to no focused view");
550                }
551            }
552            MessageInternal::UserInputMessage(view_id, user_input_message) => {
553                let view = self.get_view(view_id).context("UserInputMessage")?;
554                view.handle_user_input_message(user_input_message)?;
555            }
556            MessageInternal::OwnershipChanged(owned) => {
557                self.ownership_changed(owned);
558            }
559            MessageInternal::DropDisplayResources => {
560                self.drop_display_resources();
561            }
562            MessageInternal::FlatlandOnNextFrameBegin(view_id, info) => {
563                let view = self.get_view(view_id).context("FlatlandOnNextFrameBegin")?;
564                view.handle_on_next_frame_begin(&info);
565            }
566            MessageInternal::FlatlandOnFramePresented(view_id, info) => {
567                let view = self.get_view(view_id).context("FlatlandOnFramePresented")?;
568                view.present_done(info);
569            }
570            MessageInternal::FlatlandOnError(view_id, error) => {
571                eprintln!("flatland error view: {}, error: {:#?}", view_id, error);
572            }
573            MessageInternal::NewDisplayCoordinator(provider) => {
574                self.strategy.handle_new_display_coordinator(provider).await;
575            }
576            MessageInternal::DisplayCoordinatorListenerRequest(request) => match request {
577                CoordinatorListenerRequest::OnVsync { display_id, .. } => {
578                    if let Some(view_key) =
579                        self.strategy.get_visible_view_key_for_display(display_id.into())
580                    {
581                        if let Ok(view) = self.get_view(view_key) {
582                            view.handle_display_coordinator_listener_request(request).await;
583                        } else {
584                            // We seem to get two vsyncs after the display is removed.
585                            // Log it to help run down why that is.
586                            eprintln!("vsync for display {:?} with no view", display_id);
587                        }
588                    }
589                }
590
591                _ => self.strategy.handle_display_coordinator_event(request).await,
592            },
593        }
594        Ok(())
595    }
596
597    async fn app_init_common(&mut self) -> Result<(), Error> {
598        self.assistant.setup().context("app setup")?;
599        self.start_services()?;
600        Ok(())
601    }
602
603    /// Tests an application based on Carnelian. The `assistant` parameter will
604    /// be used to create a single new view for testing. The test will run until the
605    /// first update call, or until a five second timeout. The Result returned is the
606    /// result of the test, an Ok(()) result means the test passed.
607    pub fn test(assistant_creator_func: AssistantCreatorFunc) -> Result<(), Error> {
608        let mut executor = fasync::LocalExecutor::default();
609        let (internal_sender, mut internal_receiver) = unbounded::<MessageInternal>();
610        let f = async {
611            let app_sender = AppSender { sender: internal_sender.clone() };
612            let assistant_creator = assistant_creator_func(&app_sender);
613            let mut assistant = assistant_creator.await?;
614            Self::load_and_filter_config(&mut assistant)?;
615            let strat = create_app_strategy(&internal_sender).await?;
616            strat.create_view_for_testing(&internal_sender)?;
617            let mut app = App::new(internal_sender, strat, assistant);
618            let mut frame_count = 0;
619            app.app_init_common().await?;
620            loop {
621                let timeout =
622                    pin!(Timer::new(zx::MonotonicDuration::from_millis(500_i64).after_now()));
623                let either = futures::future::select(timeout, internal_receiver.next());
624                let resolved = either.await;
625                match resolved {
626                    Either::Left(_) => {
627                        return Err(format_err!(
628                            "Carnelian test got timeout before seeing 10 frames"
629                        ));
630                    }
631                    Either::Right((right_result, _)) => {
632                        let message = right_result.expect("message");
633                        match message {
634                            MessageInternal::Render(_) => {
635                                frame_count += 1;
636                            }
637                            _ => (),
638                        }
639                        app.handle_message(message).await.expect("handle_message failed");
640                        if frame_count > 10 {
641                            break;
642                        }
643                    }
644                }
645            }
646            Ok::<(), Error>(())
647        };
648
649        executor.run_singlethreaded(f)?;
650
651        Ok(())
652    }
653
654    fn get_focused_view_key(&self) -> Option<ViewKey> {
655        self.strategy.get_focused_view_key()
656    }
657
658    fn get_view(&mut self, view_key: ViewKey) -> Result<&mut ViewController, Error> {
659        if let Some(view) = self.view_controllers.get_mut(&view_key) {
660            Ok(view)
661        } else {
662            bail!("Could not find view controller for {}", view_key);
663        }
664    }
665
666    fn get_view_keys_for_display(&mut self, display_id: DisplayId) -> Vec<ViewKey> {
667        self.view_controllers
668            .iter()
669            .filter_map(|(view_key, view_controller)| {
670                view_controller.is_hosted_on_display(display_id).then_some(*view_key)
671            })
672            .collect()
673    }
674
675    fn close_view(&mut self, view_key: ViewKey) {
676        let view = self.view_controllers.remove(&view_key);
677        if let Some(mut view) = view {
678            view.close();
679        }
680        self.strategy.handle_view_closed(view_key);
681    }
682
683    fn ownership_changed(&mut self, owned: bool) {
684        for (_, view_controller) in &mut self.view_controllers {
685            view_controller.ownership_changed(owned);
686        }
687    }
688
689    fn drop_display_resources(&mut self) {
690        for (_, view_controller) in &mut self.view_controllers {
691            view_controller.drop_display_resources();
692        }
693    }
694
695    /// Send a message to a specific view controller. Messages not handled by the ViewController
696    /// will be forwarded to the `ViewControllerAssistant`.
697    pub fn queue_message(&mut self, target: ViewKey, msg: Message) {
698        self.messages.push((target, msg));
699    }
700
701    // Creates a view assistant for views that are using the render view mode feature, either
702    // in hosted or direct mode.
703    fn create_view_assistant(
704        &mut self,
705        view_key: ViewKey,
706        display_id: Option<DisplayId>,
707        options: Option<CreateViewOptions>,
708    ) -> Result<ViewAssistantPtr, Error> {
709        Ok(self.assistant.create_view_assistant_with_parameters(ViewCreationParameters {
710            view_key,
711            display_id,
712            app_sender: AppSender { sender: self.sender.clone() },
713            options,
714        })?)
715    }
716
717    async fn create_view_with_params(
718        &mut self,
719        params: ViewStrategyParams,
720        options: Option<CreateViewOptions>,
721    ) -> Result<(), Error> {
722        let view_key = if let Some(view_key) = params.view_key() {
723            view_key
724        } else {
725            IdGenerator2::<ViewKey>::next().expect("view_key")
726        };
727        let view_assistant = self
728            .create_view_assistant(view_key, params.display_id(), options)
729            .context("create_view_assistant")?;
730        let sender = &self.sender;
731        let view_strat = {
732            let view_strat = self
733                .strategy
734                .create_view_strategy(view_key, sender.clone(), params)
735                .await
736                .context("create_view_strategy")?;
737            self.strategy.post_setup(sender).await.context("post_setup")?;
738            view_strat
739        };
740        let view_controller =
741            ViewController::new_with_strategy(view_key, view_assistant, view_strat, sender.clone())
742                .await
743                .context("new_with_strategy")?;
744
745        self.view_controllers.insert(view_key, view_controller);
746        Ok(())
747    }
748
749    async fn create_additional_view(
750        &mut self,
751        view_key: ViewKey,
752        options: Option<CreateViewOptions>,
753    ) -> Result<(), Error> {
754        let params = self.strategy.create_view_strategy_params_for_additional_view(view_key);
755        self.create_view_with_params(params, options).await
756    }
757
758    fn close_additional_view(&mut self, view_key: ViewKey) -> Result<(), Error> {
759        self.close_view(view_key);
760        Ok(())
761    }
762
763    fn start_services(self: &mut App) -> Result<(), Error> {
764        let mut fs = component::server::ServiceFs::new_local();
765
766        self.strategy.start_services(self.sender.clone(), &mut fs)?;
767
768        let outgoing_services_names = self.assistant.outgoing_services_names();
769        let mut public = fs.dir("svc");
770        for name in outgoing_services_names {
771            let sender = self.sender.clone();
772            public.add_service_at(name, move |channel| {
773                sender
774                    .unbounded_send(MessageInternal::ServiceConnection(channel, name))
775                    .expect("unbounded_send");
776                None
777            });
778        }
779
780        match fs.take_and_serve_directory_handle() {
781            Err(e) => eprintln!("Error publishing services: {:#}", e),
782            Ok(_) => (),
783        }
784
785        fasync::Task::local(fs.collect()).detach();
786        Ok(())
787    }
788
789    pub(crate) fn image_freed(&mut self, view_id: ViewKey, image_id: u64, collection_id: u32) {
790        if let Ok(view) = self.get_view(view_id) {
791            view.image_freed(image_id, collection_id);
792        }
793    }
794
795    fn load_config() -> Result<Config, Error> {
796        const CARNELIAN_CONFIG_PATH: &str = "/pkg/data/config/carnelian.toml";
797        let config_path = PathBuf::from(CARNELIAN_CONFIG_PATH);
798        if !config_path.exists() {
799            return Ok(Config::default());
800        }
801        let config_contents = fs::read_to_string(config_path)?;
802        let config = toml::from_str(&config_contents)?;
803        Ok(config)
804    }
805}