[modular][story_provider_impl] Simplify flow for notifying of story changes.

Instead of caching only StoryInfo for a loaded story, and then
async-fetching StoryData, we cache StoryData directly. This takes an
async-read out of the NotifyStoryWatchers path.

TEST=existing

Change-Id: Ibbedce1adeedfb4eac76d4cf2c78a7abcbd97898
diff --git a/bin/sessionmgr/story_runner/story_provider_impl.cc b/bin/sessionmgr/story_runner/story_provider_impl.cc
index 902ffc3..bf0723b 100644
--- a/bin/sessionmgr/story_runner/story_provider_impl.cc
+++ b/bin/sessionmgr/story_runner/story_provider_impl.cc
@@ -132,33 +132,34 @@
             return;
             // Operation finishes since |flow| goes out of scope.
           }
-          story_info_ = CloneOptional(story_data->story_info);
-          Cont(flow);
+          Cont(std::move(story_data), flow);
         });
   }
 
-  void Cont(FlowToken flow) {
+  void Cont(fuchsia::modular::internal::StoryDataPtr story_data,
+            FlowToken flow) {
     session_storage_->GetStoryStorage(story_id_)->WeakThen(
         GetWeakPtr(),
-        [this, flow](std::unique_ptr<StoryStorage> story_storage) {
-          struct StoryRuntimeContainer container;
-          container.storage = std::move(story_storage);
-          container.controller_impl = std::make_unique<StoryControllerImpl>(
-              story_id_, session_storage_, container.storage.get(),
-              story_provider_impl_);
-          container.current_info = std::move(story_info_);
-          container.entity_provider =
-              std::make_unique<StoryEntityProvider>(container.storage.get());
-          auto it = story_provider_impl_->story_runtime_containers_.emplace(
-              story_id_, std::move(container));
-          story_controller_container_ = &it.first->second;
-        });
+        fxl::MakeCopyable(
+            [this, story_data = std::move(story_data),
+             flow](std::unique_ptr<StoryStorage> story_storage) mutable {
+              struct StoryRuntimeContainer container;
+              container.storage = std::move(story_storage);
+              container.controller_impl = std::make_unique<StoryControllerImpl>(
+                  story_id_, session_storage_, container.storage.get(),
+                  story_provider_impl_);
+              container.current_data = std::move(story_data);
+              container.entity_provider = std::make_unique<StoryEntityProvider>(
+                  container.storage.get());
+              auto it = story_provider_impl_->story_runtime_containers_.emplace(
+                  story_id_, std::move(container));
+              story_controller_container_ = &it.first->second;
+            }));
   }
 
   StoryProviderImpl* const story_provider_impl_;  // not owned
   SessionStorage* const session_storage_;         // not owned
   const fidl::StringPtr story_id_;
-  fuchsia::modular::StoryInfoPtr story_info_;
 
   StoryRuntimeContainer* story_controller_container_ = nullptr;
 
@@ -348,7 +349,7 @@
   auto watcher_ptr = watcher.Bind();
   for (const auto& item : story_runtime_containers_) {
     const auto& container = item.second;
-    watcher_ptr->OnChange(CloneStruct(*container.current_info),
+    watcher_ptr->OnChange(CloneStruct(container.current_data->story_info),
                           container.controller_impl->GetStoryState(),
                           container.controller_impl->GetStoryVisibilityState());
   }
@@ -450,27 +451,15 @@
 void StoryProviderImpl::NotifyStoryStateChange(
     fidl::StringPtr story_id, const fuchsia::modular::StoryState story_state,
     const fuchsia::modular::StoryVisibilityState story_visibility_state) {
-  auto on_run =
-      Future<>::Create("StoryProviderImpl.NotifyStoryStateChange.on_run");
-  auto done = on_run
-                  ->AsyncMap([this, story_id] {
-                    return session_storage_->GetStoryData(story_id);
-                  })
-                  ->Then([this, story_id, story_state, story_visibility_state](
-                             fuchsia::modular::internal::StoryDataPtr data) {
-                    auto it = story_runtime_containers_.find(story_id);
-                    if (it == story_runtime_containers_.end()) {
-                      // If this call arrives while DeleteStory() is in
-                      // progress, the story controller might already be gone
-                      // from here.
-                      return;
-                    }
-                    NotifyStoryWatchers(data.get(), story_state,
-                                        story_visibility_state);
-                  });
-  std::function<void()> callback = [] {};
-  operation_queue_.Add(WrapFutureAsOperation(
-      "StoryProviderImpl::NotifyStoryStateChange", on_run, done, callback));
+  auto it = story_runtime_containers_.find(story_id);
+  if (it == story_runtime_containers_.end()) {
+    // If this call arrives while DeleteStory() is in
+    // progress, the story controller might already be gone
+    // from here.
+    return;
+  }
+  NotifyStoryWatchers(it->second.current_data.get(), story_state,
+                      story_visibility_state);
 }
 
 void StoryProviderImpl::NotifyStoryActivityChange(
@@ -569,12 +558,10 @@
 void StoryProviderImpl::OnStoryStorageUpdated(
     fidl::StringPtr story_id,
     fuchsia::modular::internal::StoryData story_data) {
-  // HACK(jimbe) We don't have the page and it's expensive to get it, so
-  // just mark it as STOPPED. We know it's not running or we'd have a
-  // fuchsia::modular::StoryController.
+  // If we have a StoryRuntimeContainer for this story id, update our cached
+  // StoryData and get runtime state available from it.
   //
-  // If we have a StoryControllerImpl for this story id, update our cached
-  // fuchsia::modular::StoryInfo.
+  // Otherwise, use defaults for an unloaded story.
   fuchsia::modular::StoryState state = fuchsia::modular::StoryState::STOPPED;
   fuchsia::modular::StoryVisibilityState visibility_state =
       fuchsia::modular::StoryVisibilityState::DEFAULT;
@@ -582,9 +569,8 @@
   if (i != story_runtime_containers_.end()) {
     state = i->second.controller_impl->GetStoryState();
     visibility_state = i->second.controller_impl->GetStoryVisibilityState();
-    i->second.current_info = CloneOptional(story_data.story_info);
+    i->second.current_data = CloneOptional(story_data);
   }
-
   NotifyStoryWatchers(&story_data, state, visibility_state);
 }
 
@@ -632,7 +618,7 @@
 }
 
 void StoryProviderImpl::NotifyStoryWatchers(
-    const fuchsia::modular::internal::StoryData* const story_data,
+    const fuchsia::modular::internal::StoryData* story_data,
     const fuchsia::modular::StoryState story_state,
     const fuchsia::modular::StoryVisibilityState story_visibility_state) {
   if (!story_data || story_data->story_options.kind_of_proto_story) {
diff --git a/bin/sessionmgr/story_runner/story_provider_impl.h b/bin/sessionmgr/story_runner/story_provider_impl.h
index 625abbe..8aac267 100644
--- a/bin/sessionmgr/story_runner/story_provider_impl.h
+++ b/bin/sessionmgr/story_runner/story_provider_impl.h
@@ -210,7 +210,7 @@
                              fuchsia::modular::internal::StoryData story_data);
 
   void NotifyStoryWatchers(
-      const fuchsia::modular::internal::StoryData* const story_data,
+      const fuchsia::modular::internal::StoryData* story_data,
       fuchsia::modular::StoryState story_state,
       fuchsia::modular::StoryVisibilityState story_visibility_state);
 
@@ -247,14 +247,13 @@
   // 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 fuchsia::modular::StoryInfo for every
-  // story, to send it to newly registered story provider watchers, and to story
-  // provider watchers when only the story state changes.
+  // 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 {
     std::unique_ptr<StoryControllerImpl> controller_impl;
     std::unique_ptr<StoryStorage> storage;
     std::unique_ptr<StoryEntityProvider> entity_provider;
-    fuchsia::modular::StoryInfoPtr current_info;
+    fuchsia::modular::internal::StoryDataPtr current_data;
   };
   std::map<std::string, StoryRuntimeContainer> story_runtime_containers_;