| // Copyright 2016 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. |
| |
| #ifndef PERIDOT_BIN_SESSIONMGR_STORY_RUNNER_STORY_PROVIDER_IMPL_H_ |
| #define PERIDOT_BIN_SESSIONMGR_STORY_RUNNER_STORY_PROVIDER_IMPL_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <set> |
| |
| #include <fuchsia/ledger/cpp/fidl.h> |
| #include <fuchsia/modular/cpp/fidl.h> |
| #include <fuchsia/modular/internal/cpp/fidl.h> |
| #include <fuchsia/scenic/snapshot/cpp/fidl.h> |
| #include <fuchsia/ui/policy/cpp/fidl.h> |
| #include <fuchsia/ui/viewsv1/cpp/fidl.h> |
| #include <fuchsia/ui/viewsv1token/cpp/fidl.h> |
| #include <lib/async/cpp/operation.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/fidl/cpp/interface_ptr.h> |
| #include <lib/fidl/cpp/interface_ptr_set.h> |
| #include <lib/fidl/cpp/interface_request.h> |
| #include <lib/fidl/cpp/string.h> |
| #include <lib/fit/function.h> |
| #include <lib/fxl/macros.h> |
| |
| #include "peridot/bin/sessionmgr/agent_runner/agent_runner.h" |
| #include "peridot/bin/sessionmgr/component_context_impl.h" |
| #include "peridot/bin/sessionmgr/message_queue/message_queue_manager.h" |
| #include "peridot/bin/sessionmgr/story/system.h" |
| #include "peridot/bin/sessionmgr/story/model/story_model_owner.h" |
| #include "peridot/bin/sessionmgr/story/model/noop_story_model_storage.h" |
| #include "peridot/bin/sessionmgr/story_runner/story_entity_provider.h" |
| #include "peridot/lib/fidl/app_client.h" |
| #include "peridot/lib/fidl/environment.h" |
| #include "peridot/lib/fidl/proxy.h" |
| #include "peridot/lib/ledger_client/ledger_client.h" |
| #include "peridot/lib/ledger_client/page_client.h" |
| #include "peridot/lib/ledger_client/types.h" |
| #include "peridot/lib/module_manifest/module_facet_reader.h" |
| |
| namespace modular { |
| |
| class PresentationProvider; |
| class Resolver; |
| class SessionStorage; |
| class StoryControllerImpl; |
| class StoryStorage; |
| |
| class StoryProviderImpl : fuchsia::modular::StoryProvider, |
| fuchsia::modular::FocusWatcher { |
| public: |
| StoryProviderImpl( |
| Environment* user_environment, std::string device_id, |
| SessionStorage* session_storage, fuchsia::modular::AppConfig story_shell, |
| const ComponentContextInfo& component_context_info, |
| fuchsia::modular::FocusProviderPtr focus_provider, |
| fuchsia::modular::UserIntelligenceProvider* user_intelligence_provider, |
| fuchsia::modular::ModuleResolver* module_resolver, |
| EntityProviderRunner* entity_provider_runner, |
| modular::ModuleFacetReader* module_facet_reader, |
| PresentationProvider* presentation_provider, |
| fuchsia::ui::viewsv1::ViewSnapshotPtr view_snapshot, bool test); |
| |
| ~StoryProviderImpl() override; |
| |
| void Connect(fidl::InterfaceRequest<fuchsia::modular::StoryProvider> request); |
| |
| // Used when the session shell is swapped. |
| void StopAllStories(const std::function<void()>& callback); |
| |
| // The session shell to send story views to. It is not a constructor argument |
| // because it is updated when the session shell is swapped. |
| void SetSessionShell(fuchsia::modular::SessionShellPtr session_shell); |
| |
| // Stops serving the fuchsia::modular::StoryProvider interface and stops all |
| // stories. |
| void Teardown(const std::function<void()>& callback); |
| |
| // Called by StoryControllerImpl. |
| const Environment* user_environment() const { return user_environment_; } |
| |
| // The device ID for this user/device. |
| const std::string device_id() const { return device_id_; } |
| |
| // Called by StoryControllerImpl. |
| const ComponentContextInfo& component_context_info() { |
| return component_context_info_; |
| } |
| |
| // Called by StoryControllerImpl. |
| fuchsia::modular::UserIntelligenceProvider* user_intelligence_provider() { |
| return user_intelligence_provider_; |
| } |
| |
| // Called by StoryControllerImpl. |
| fuchsia::modular::ModuleResolver* module_resolver() { |
| return module_resolver_; |
| } |
| |
| fuchsia::modular::EntityResolver* entity_resolver() { |
| return entity_provider_runner_; |
| } |
| |
| modular::ModuleFacetReader* module_facet_reader() { |
| return module_facet_reader_; |
| } |
| |
| // Called by StoryControllerImpl. |
| const fuchsia::modular::AppConfig& story_shell() const { |
| return story_shell_; |
| } |
| |
| // Called by StoryControllerImpl. |
| // |
| // Returns an AppClient rather than taking an interface request |
| // as an argument because the application is preloaded. |
| std::unique_ptr<AppClient<fuchsia::modular::Lifecycle>> StartStoryShell( |
| fidl::StringPtr story_id, |
| fidl::InterfaceRequest<fuchsia::ui::viewsv1token::ViewOwner> request); |
| |
| // Called by StoryControllerImpl. |
| // |
| // Returns nullptr if the StoryInfo for |story_id| is not cached. |
| fuchsia::modular::StoryInfoPtr GetCachedStoryInfo(fidl::StringPtr story_id); |
| |
| // |fuchsia::modular::StoryProvider|. |
| void GetStoryInfo(fidl::StringPtr story_id, |
| GetStoryInfoCallback callback) override; |
| |
| // Called by StoryControllerImpl. Sends request to |
| // fuchsia::modular::FocusProvider |
| void RequestStoryFocus(fidl::StringPtr story_id); |
| |
| // Called by StoryControllerImpl. Sends, using AttachView(), the view of the |
| // story identified by |story_id| to the current session shell. |
| void AttachView(fidl::StringPtr story_id, |
| fuchsia::ui::viewsv1token::ViewOwnerPtr view_owner); |
| |
| // Called by StoryControllerImpl. Notifies, using DetachView(), the current |
| // session shell that the view of the story identified by |story_id| is about |
| // to close. |
| void DetachView(fidl::StringPtr story_id, std::function<void()> done); |
| |
| // Called by StoryControllerImpl. |
| void NotifyStoryStateChange(fidl::StringPtr story_id); |
| |
| // Called by StoryControllerImpl. |
| void NotifyStoryActivityChange( |
| fidl::StringPtr story_id, |
| fidl::VectorPtr<fuchsia::modular::OngoingActivityType> |
| ongoing_activities); |
| |
| // Called by StoryControllerImpl. Sends request to |
| // fuchsia::modular::SessionShell through PresentationProvider. |
| void GetPresentation( |
| fidl::StringPtr story_id, |
| fidl::InterfaceRequest<fuchsia::ui::policy::Presentation> request); |
| void WatchVisualState( |
| fidl::StringPtr story_id, |
| fidl::InterfaceHandle<fuchsia::modular::StoryVisualStateWatcher> watcher); |
| |
| // Called by StoryControllerImpl. Takes a snapshot of the story by the given |
| // |story_id|. Callback is returned with the snapshot of the story, or an |
| // empty buffer (size == 0) if the snapshot could not be taken. |
| void TakeSnapshot(fidl::StringPtr story_id, |
| fit::function<void(fuchsia::mem::Buffer)> callback); |
| |
| // Called by StoryControllerImpl. Creates a new view with the given |
| // |view_owner_request| and connects the snapshot loader with the given |
| // |loader_request|. |
| void StartSnapshotLoader( |
| fidl::InterfaceRequest<fuchsia::ui::viewsv1token::ViewOwner> |
| view_owner_request, |
| fidl::InterfaceRequest<fuchsia::scenic::snapshot::Loader> loader_request); |
| |
| // Creates an entity with the specified |type| and |data| in the story with |
| // |story_id|. |
| // |
| // |callback| will be called with a reference to the created entity. If the |
| // creation failed the |entity_request| is dropped. |
| void CreateEntity( |
| const std::string& story_id, fidl::StringPtr type, |
| fuchsia::mem::Buffer data, |
| fidl::InterfaceRequest<fuchsia::modular::Entity> entity_request, |
| std::function<void(std::string /* entity_reference */)> callback); |
| |
| // Creates an entity with the specified |type| and |data| in the story with |
| // |story_id|. |
| // |
| // The story provider guarantees the uniqueness of the EntityProvider |
| // associated with any given story. |
| void ConnectToStoryEntityProvider( |
| const std::string& story_id, |
| fidl::InterfaceRequest<fuchsia::modular::EntityProvider> |
| entity_provider_request); |
| |
| private: |
| // |fuchsia::modular::StoryProvider| |
| void GetController(fidl::StringPtr story_id, |
| fidl::InterfaceRequest<fuchsia::modular::StoryController> |
| request) override; |
| |
| // |fuchsia::modular::StoryProvider| |
| void GetStories( |
| fidl::InterfaceHandle<fuchsia::modular::StoryProviderWatcher> watcher, |
| PreviousStoriesCallback callback) override; |
| |
| // |fuchsia::modular::StoryProvider| |
| void PreviousStories(PreviousStoriesCallback callback) override; |
| |
| // |fuchsia::modular::StoryProvider| |
| void Watch(fidl::InterfaceHandle<fuchsia::modular::StoryProviderWatcher> |
| watcher) override; |
| |
| // |fuchsia::modular::StoryProvider| |
| void WatchActivity( |
| fidl::InterfaceHandle<fuchsia::modular::StoryActivityWatcher> watcher) |
| override; |
| |
| // |fuchsia::modular::FocusWatcher| |
| void OnFocusChange(fuchsia::modular::FocusInfoPtr info) override; |
| |
| // Called by *session_storage_. |
| void OnStoryStorageDeleted(fidl::StringPtr story_id); |
| void OnStoryStorageUpdated(fidl::StringPtr story_id, |
| fuchsia::modular::internal::StoryData story_data); |
| |
| void NotifyStoryWatchers( |
| const fuchsia::modular::internal::StoryData* story_data, |
| fuchsia::modular::StoryState story_state, |
| fuchsia::modular::StoryVisibilityState story_visibility_state); |
| |
| void MaybeLoadStoryShell(); |
| |
| void MaybeLoadStoryShellDelayed(); |
| |
| Environment* const user_environment_; |
| |
| SessionStorage* session_storage_; // Not owned. |
| |
| // The service from the session shell run by the sessionmgr. Owned here |
| // because only used from here. |
| fuchsia::modular::SessionShellPtr session_shell_; |
| |
| // Unique ID generated for this user/device combination. |
| const std::string device_id_; |
| |
| // The bindings for this instance. |
| fidl::BindingSet<fuchsia::modular::StoryProvider> bindings_; |
| |
| // Used to preload story shell before it is requested. |
| fuchsia::modular::AppConfig story_shell_; |
| std::unique_ptr<AppClient<fuchsia::modular::Lifecycle>> |
| preloaded_story_shell_app_; |
| |
| // When running in a test, we don't preload story shells, because then the |
| // preloaded next instance of the story doesn't pass its test points. |
| const bool test_; |
| |
| fidl::InterfacePtrSet<fuchsia::modular::StoryProviderWatcher> watchers_; |
| fidl::InterfacePtrSet<fuchsia::modular::StoryActivityWatcher> |
| activity_watchers_; |
| |
| // The story controllers of the currently active stories, indexed by their |
| // story IDs. |
| // |
| // Only user logout or delete story calls ever remove story controllers from |
| // this collection, but controllers for stopped stories stay in it. |
| // |
| // Also keeps a cached version of the StoryData for every story so it does |
| // not have to be loaded from disk when querying about this story. |
| struct StoryRuntimeContainer { |
| // The executor on which asynchronous tasks are scheduled for this story. |
| // |
| // TODO(thatguy): Migrate all operations under |controller_impl| to use |
| // fit::promise and |executor|. MF-117 |
| // TODO(thatguy): Once fit::scope is complete, share one executor for the |
| // whole process and take advantage of fit::scope to auto-cancel tasks when |
| // |this| dies. |
| std::unique_ptr<fit::executor> executor; |
| |
| // StoryRuntime itself contains a StoryModelOwner and manages systems with |
| // asynchronous initialization and teardown operations. |
| std::unique_ptr<StoryModelOwner> model_owner; |
| |
| // For ease of memory management, we store all runtime systems in |
| // |systems|. |
| std::vector<std::unique_ptr<System>> systems; |
| |
| // This allows us to observe changes to the StoryModel owned by |runtime|. |
| std::unique_ptr<StoryObserver> model_observer; |
| |
| // NOTE: The following are transitioning to StoryModel and associated |
| // classes above, as outlined in MF-85. |
| std::unique_ptr<StoryControllerImpl> controller_impl; |
| std::unique_ptr<StoryStorage> storage; |
| std::unique_ptr<StoryEntityProvider> entity_provider; |
| fuchsia::modular::internal::StoryDataPtr current_data; |
| }; |
| std::map<std::string, StoryRuntimeContainer> story_runtime_containers_; |
| |
| const ComponentContextInfo component_context_info_; |
| |
| fuchsia::modular::UserIntelligenceProvider* const |
| user_intelligence_provider_; // Not owned. |
| fuchsia::modular::ModuleResolver* const module_resolver_; // Not owned. |
| EntityProviderRunner* const entity_provider_runner_; // Not owned. |
| modular::ModuleFacetReader* const module_facet_reader_; // Not owned. |
| PresentationProvider* const presentation_provider_; // Not owned. |
| |
| // When a story gets created, or when it gets focused on this device, we write |
| // a record of the current context in the story page. So we need to watch the |
| // context and the focus. This serves to compute relative importance of |
| // stories in the timeline, as determined by the current context. |
| fuchsia::modular::FocusProviderPtr focus_provider_; |
| fidl::Binding<fuchsia::modular::FocusWatcher> focus_watcher_binding_; |
| |
| // Service provided by scenic to take snapshots of stories. |
| fuchsia::ui::viewsv1::ViewSnapshotPtr view_snapshot_; |
| |
| // Cached mapping of story ID's to the story view koids. Used as a token to |
| // take snapshots of stories. This is a temporary hack because koids are |
| // guessable. The intention is to have this hack until the framework is |
| // provided with a more secure API from scenic to take snapshots, which is |
| // TBD. |
| std::map<fidl::StringPtr, zx_koid_t> view_endpoints_; |
| |
| // Snapshot loader component which is used to create new snapshot views. There |
| // is only one instance of this component running per session. |
| std::unique_ptr<AppClient<fuchsia::modular::Lifecycle>> snapshot_loader_app_; |
| |
| // This is a container of all operations that are currently enqueued to run in |
| // a FIFO manner. All operations exposed via |fuchsia::modular::StoryProvider| |
| // interface are queued here. |
| // |
| // The advantage of doing this is that if an operation consists of multiple |
| // asynchronous calls then no state needs to be maintained for incomplete / |
| // pending operations. |
| // |
| // TODO(mesch): If a story provider operation invokes a story operation that |
| // causes the story updating its story info state, that update operation gets |
| // scheduled on this queue again, after the current operation. It would be |
| // better to be able to schedule such an operation on the story queue because |
| // it's a per story operation even if it affects the per story key in the root |
| // page, and then the update of story info is bounded by the outer operation. |
| OperationQueue operation_queue_; |
| |
| fxl::WeakPtrFactory<StoryProviderImpl> weak_factory_; |
| |
| // Operations implemented here. |
| class LoadStoryRuntimeCall; |
| class StopStoryCall; |
| class StopAllStoriesCall; |
| class StopStoryShellCall; |
| class GetStoryEntityProviderCall; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(StoryProviderImpl); |
| }; |
| |
| } // namespace modular |
| |
| #endif // PERIDOT_BIN_SESSIONMGR_STORY_RUNNER_STORY_PROVIDER_IMPL_H_ |