Revert "Replace flutter_runner::Thread with fml::Thread (#26783)"

This reverts commit 46178d6cdbcbcc9960457542b93b4d0c70d2586f.
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 0084c7e..508b8e9 100755
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -231,8 +231,6 @@
 FILE: ../../../flutter/fml/platform/fuchsia/message_loop_fuchsia.cc
 FILE: ../../../flutter/fml/platform/fuchsia/message_loop_fuchsia.h
 FILE: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc
-FILE: ../../../flutter/fml/platform/fuchsia/task_observers.cc
-FILE: ../../../flutter/fml/platform/fuchsia/task_observers.h
 FILE: ../../../flutter/fml/platform/linux/message_loop_linux.cc
 FILE: ../../../flutter/fml/platform/linux/message_loop_linux.h
 FILE: ../../../flutter/fml/platform/linux/paths_linux.cc
@@ -1421,6 +1419,8 @@
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/keyboard.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/keyboard_unittest.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/logging.h
+FILE: ../../../flutter/shell/platform/fuchsia/flutter/loop.cc
+FILE: ../../../flutter/shell/platform/fuchsia/flutter/loop.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/main.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/aot_product_runtime
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/aot_runtime
@@ -1440,8 +1440,12 @@
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/runner_unittest.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.h
+FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_observers.cc
+FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_observers.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_runner_adapter.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h
+FILE: ../../../flutter/shell/platform/fuchsia/flutter/thread.cc
+FILE: ../../../flutter/shell/platform/fuchsia/flutter/thread.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/unique_fdio_ns.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.h
diff --git a/fml/BUILD.gn b/fml/BUILD.gn
index 5c8432e..d65da2a 100644
--- a/fml/BUILD.gn
+++ b/fml/BUILD.gn
@@ -186,8 +186,6 @@
       "platform/fuchsia/message_loop_fuchsia.cc",
       "platform/fuchsia/message_loop_fuchsia.h",
       "platform/fuchsia/paths_fuchsia.cc",
-      "platform/fuchsia/task_observers.cc",
-      "platform/fuchsia/task_observers.h",
     ]
 
     public_deps += [
diff --git a/fml/platform/fuchsia/message_loop_fuchsia.cc b/fml/platform/fuchsia/message_loop_fuchsia.cc
index 0fac826..9a3c1c0 100644
--- a/fml/platform/fuchsia/message_loop_fuchsia.cc
+++ b/fml/platform/fuchsia/message_loop_fuchsia.cc
@@ -8,25 +8,11 @@
 #include <lib/async/cpp/task.h>
 #include <lib/async/default.h>
 #include <lib/zx/time.h>
-#include "flutter/fml/platform/fuchsia/task_observers.h"
 
 namespace fml {
 
-namespace {
-
-// See comment on `ExecuteAfterTaskObservers` for explanation.
-static void LoopEpilogue(async_loop_t*, void*) {
-  ExecuteAfterTaskObservers();
-}
-
-constexpr async_loop_config_t kLoopConfig = {
-    .make_default_for_current_thread = false,
-    .epilogue = &LoopEpilogue,
-};
-
-}  // namespace
-
-MessageLoopFuchsia::MessageLoopFuchsia() : loop_(&kLoopConfig) {
+MessageLoopFuchsia::MessageLoopFuchsia()
+    : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
   async_set_default_dispatcher(loop_.dispatcher());
 }
 
diff --git a/fml/platform/fuchsia/task_observers.h b/fml/platform/fuchsia/task_observers.h
deleted file mode 100644
index de3c2e4..0000000
--- a/fml/platform/fuchsia/task_observers.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2013 The Flutter 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 FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_
-#define FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_
-
-#include <lib/fit/function.h>
-
-namespace fml {
-
-// Executes all closures that were registered via
-// `CurrentMessageLoopAddAfterTaskObserver` on this thread.
-//
-// WARNING(fxbug.dev/77957): These task observers are distinct from the task
-// observers that can be specified via `fml::MessageLoop::AddTaskObserver` and
-// they behave differently!
-//
-// Task observers registered via `fml::MessageLoop::AddTaskObserver` only fire
-// after work that was posted via the `fml::MessageLoop`'s `TaskRunner`
-// completes. Work that is posted directly to the Fuchsia message loop (e.g.
-// using `async::PostTask(async_get_default_dispatcher(), ...)`) is invisible to
-// `fml::MessageLoop`, so the `fml::MessageLoop`'s task observers don't fire.
-//
-// The task observers registered with `CurrentMessageLoopAddAfterTaskObserver`,
-// however, fire after _every_ work item is completed, regardless of whether it
-// was posted to the Fuchsia message loop directly or via `fml::MessageLoop`.
-//
-// These two mechanisms are redundant and confusing, so we should fix it
-// somehow.
-void ExecuteAfterTaskObservers();
-
-void CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
-                                            fit::closure observer);
-
-void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key);
-
-}  // namespace fml
-
-#endif  // FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_
diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn
index 70dae94..5e36a86 100644
--- a/shell/platform/fuchsia/flutter/BUILD.gn
+++ b/shell/platform/fuchsia/flutter/BUILD.gn
@@ -70,14 +70,20 @@
       "keyboard.cc",
       "keyboard.h",
       "logging.h",
+      "loop.cc",
+      "loop.h",
       "platform_view.cc",
       "platform_view.h",
       "runner.cc",
       "runner.h",
       "surface.cc",
       "surface.h",
+      "task_observers.cc",
+      "task_observers.h",
       "task_runner_adapter.cc",
       "task_runner_adapter.h",
+      "thread.cc",
+      "thread.h",
       "unique_fdio_ns.h",
       "vsync_waiter.cc",
       "vsync_waiter.h",
@@ -211,17 +217,10 @@
     # C++ stack.
     cflags = [ "-fno-omit-frame-pointer" ]
 
-    if (invoker.product) {
-      # Fuchsia's default stack size was resulting in test failures in a
-      # downstream project. Provide some extra room.
-      ldflags = [ "-Wl,-z,stack-size=0x100000" ]
-    } else {
+    if (!invoker.product) {
       # This flag is needed so that the call to dladdr() in Dart's native symbol
       # resolver can report good symbol information for the CPU profiler.
-      ldflags = [
-        "-Wl,-z,stack-size=0x100000",
-        "-rdynamic",
-      ]
+      ldflags = [ "-rdynamic" ]
     }
   }
 }
diff --git a/shell/platform/fuchsia/flutter/component.cc b/shell/platform/fuchsia/flutter/component.cc
index 3f75c3b..2999a81 100644
--- a/shell/platform/fuchsia/flutter/component.cc
+++ b/shell/platform/fuchsia/flutter/component.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#define FML_USED_ON_EMBEDDER
-
 #include "component.h"
 
 #include <dlfcn.h>
@@ -29,7 +27,6 @@
 #include <sstream>
 
 #include "flutter/fml/mapping.h"
-#include "flutter/fml/platform/fuchsia/task_observers.h"
 #include "flutter/fml/synchronization/waitable_event.h"
 #include "flutter/fml/unique_fd.h"
 #include "flutter/runtime/dart_vm_lifecycle.h"
@@ -40,6 +37,9 @@
 #include "runtime/dart/utils/tempfs.h"
 #include "runtime/dart/utils/vmo.h"
 
+#include "task_observers.h"
+#include "task_runner_adapter.h"
+
 // TODO(kaushikiska): Use these constants from ::llcpp::fuchsia::io
 // Can read from target object.
 constexpr uint32_t OPEN_RIGHT_READABLE = 1u;
@@ -186,11 +186,11 @@
     fuchsia::sys::StartupInfo startup_info,
     std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
     fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
-  auto thread = std::make_unique<fml::Thread>();
+  std::unique_ptr<Thread> thread = std::make_unique<Thread>();
   std::unique_ptr<Application> application;
 
   fml::AutoResetWaitableEvent latch;
-  thread->GetTaskRunner()->PostTask([&]() mutable {
+  async::PostTask(thread->dispatcher(), [&]() mutable {
     application.reset(
         new Application(std::move(termination_callback), std::move(package),
                         std::move(startup_info), runner_incoming_services,
@@ -199,8 +199,7 @@
   });
 
   latch.Wait();
-  return {.platform_thread = std::move(thread),
-          .application = std::move(application)};
+  return {.thread = std::move(thread), .application = std::move(application)};
 }
 
 Application::Application(
@@ -492,11 +491,11 @@
   settings_.leak_vm = false;
 
   settings_.task_observer_add =
-      std::bind(&fml::CurrentMessageLoopAddAfterTaskObserver,
-                std::placeholders::_1, std::placeholders::_2);
+      std::bind(&CurrentMessageLoopAddAfterTaskObserver, std::placeholders::_1,
+                std::placeholders::_2);
 
   settings_.task_observer_remove = std::bind(
-      &fml::CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1);
+      &CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1);
 
   settings_.log_message_callback = [](const std::string& tag,
                                       const std::string& message) {
@@ -518,7 +517,8 @@
 #endif  // defined(__aarch64__)
 
   auto weak_application = weak_factory_.GetWeakPtr();
-  auto platform_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
+  auto platform_task_runner =
+      CreateFMLTaskRunner(async_get_default_dispatcher());
   const std::string component_url = package.resolved_url;
   settings_.unhandled_exception_callback = [weak_application,
                                             platform_task_runner,
diff --git a/shell/platform/fuchsia/flutter/component.h b/shell/platform/fuchsia/flutter/component.h
index 7955c10..df9498b 100644
--- a/shell/platform/fuchsia/flutter/component.h
+++ b/shell/platform/fuchsia/flutter/component.h
@@ -26,6 +26,7 @@
 
 #include "engine.h"
 #include "flutter_runner_product_configuration.h"
+#include "thread.h"
 #include "unique_fdio_ns.h"
 
 namespace flutter_runner {
@@ -33,12 +34,12 @@
 class Application;
 
 struct ActiveApplication {
-  std::unique_ptr<fml::Thread> platform_thread;
+  std::unique_ptr<Thread> thread;
   std::unique_ptr<Application> application;
 
   ActiveApplication& operator=(ActiveApplication&& other) noexcept {
     if (this != &other) {
-      this->platform_thread.reset(other.platform_thread.release());
+      this->thread.reset(other.thread.release());
       this->application.reset(other.application.release());
     }
     return *this;
diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc
index 0c5c615..c3de46b 100644
--- a/shell/platform/fuchsia/flutter/engine.cc
+++ b/shell/platform/fuchsia/flutter/engine.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#define FML_USED_ON_EMBEDDER
-
 #include "engine.h"
 
 #include <lib/async/cpp/task.h>
@@ -12,7 +10,6 @@
 #include "flutter/common/graphics/persistent_cache.h"
 #include "flutter/common/task_runners.h"
 #include "flutter/fml/make_copyable.h"
-#include "flutter/fml/message_loop.h"
 #include "flutter/fml/synchronization/waitable_event.h"
 #include "flutter/fml/task_runner.h"
 #include "flutter/runtime/dart_vm_lifecycle.h"
@@ -29,6 +26,7 @@
 #include "fuchsia_intl.h"
 #include "platform_view.h"
 #include "surface.h"
+#include "task_runner_adapter.h"
 #include "vsync_waiter.h"
 
 namespace flutter_runner {
@@ -76,15 +74,12 @@
       weak_factory_(this) {
   // Get the task runners from the managed threads. The current thread will be
   // used as the "platform" thread.
-  fml::RefPtr<fml::TaskRunner> platform_task_runner =
-      fml::MessageLoop::GetCurrent().GetTaskRunner();
-
   const flutter::TaskRunners task_runners(
-      thread_label_,                // Dart thread labels
-      platform_task_runner,         // platform
-      threads_[0].GetTaskRunner(),  // raster
-      threads_[1].GetTaskRunner(),  // ui
-      threads_[2].GetTaskRunner()   // io
+      thread_label_,  // Dart thread labels
+      CreateFMLTaskRunner(async_get_default_dispatcher()),  // platform
+      CreateFMLTaskRunner(threads_[0].dispatcher()),        // raster
+      CreateFMLTaskRunner(threads_[1].dispatcher()),        // ui
+      CreateFMLTaskRunner(threads_[2].dispatcher())         // io
   );
   UpdateNativeThreadLabelNames(thread_label_, task_runners);
 
@@ -121,9 +116,10 @@
   // This handles the fidl error callback when the Session connection is
   // broken. The SessionListener interface also has an OnError method, which is
   // invoked on the platform thread (in PlatformView).
-  fml::closure session_error_callback = [task_runner = platform_task_runner,
+  fml::closure session_error_callback = [dispatcher =
+                                             async_get_default_dispatcher(),
                                          weak = weak_factory_.GetWeakPtr()]() {
-    task_runner->PostTask([weak]() {
+    async::PostTask(dispatcher, [weak]() {
       if (weak) {
         weak->Terminate();
       }
@@ -212,9 +208,9 @@
   // platform thread when that happens. The Session itself should also be
   // disconnected when this happens, and it will also attempt to terminate.
   fit::closure on_session_listener_error_callback =
-      [task_runner = platform_task_runner,
+      [dispatcher = async_get_default_dispatcher(),
        weak = weak_factory_.GetWeakPtr()]() {
-        task_runner->PostTask([weak]() {
+        async::PostTask(dispatcher, [weak]() {
           if (weak) {
             weak->Terminate();
           }
@@ -485,6 +481,9 @@
 Engine::~Engine() {
   shell_.reset();
   for (auto& thread : threads_) {
+    thread.Quit();
+  }
+  for (auto& thread : threads_) {
     thread.Join();
   }
 }
diff --git a/shell/platform/fuchsia/flutter/engine.h b/shell/platform/fuchsia/flutter/engine.h
index 33c704f..bd4cb94 100644
--- a/shell/platform/fuchsia/flutter/engine.h
+++ b/shell/platform/fuchsia/flutter/engine.h
@@ -27,6 +27,7 @@
 #include "fuchsia_external_view_embedder.h"
 #include "gfx_session_connection.h"
 #include "isolate_configurator.h"
+#include "thread.h"
 #include "vulkan_surface_producer.h"
 
 namespace flutter_runner {
@@ -68,7 +69,7 @@
   Delegate& delegate_;
 
   const std::string thread_label_;
-  std::array<fml::Thread, 3> threads_;
+  std::array<Thread, 3> threads_;
 
   std::shared_ptr<GfxSessionConnection> session_connection_;
   std::optional<VulkanSurfaceProducer> surface_producer_;
diff --git a/shell/platform/fuchsia/flutter/fuchsia_intl.cc b/shell/platform/fuchsia/flutter/fuchsia_intl.cc
index 85c91b4..b323538 100644
--- a/shell/platform/fuchsia/flutter/fuchsia_intl.cc
+++ b/shell/platform/fuchsia/flutter/fuchsia_intl.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "loop.h"
 #include "rapidjson/document.h"
 #include "rapidjson/stringbuffer.h"
 #include "rapidjson/writer.h"
diff --git a/shell/platform/fuchsia/flutter/loop.cc b/shell/platform/fuchsia/flutter/loop.cc
new file mode 100644
index 0000000..6518828
--- /dev/null
+++ b/shell/platform/fuchsia/flutter/loop.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "loop.h"
+
+#include <lib/async-loop/loop.h>
+#include <lib/async/default.h>
+
+#include "task_observers.h"
+
+namespace flutter_runner {
+
+namespace {
+
+static void LoopEpilogue(async_loop_t*, void*) {
+  ExecuteAfterTaskObservers();
+}
+
+constexpr async_loop_config_t kAttachedLoopConfig = {
+    .default_accessors =
+        {
+            .getter = async_get_default_dispatcher,
+            .setter = async_set_default_dispatcher,
+        },
+    .make_default_for_current_thread = true,
+    .epilogue = &LoopEpilogue,
+};
+
+constexpr async_loop_config_t kDetachedLoopConfig = {
+    .default_accessors =
+        {
+            .getter = async_get_default_dispatcher,
+            .setter = async_set_default_dispatcher,
+        },
+    .make_default_for_current_thread = false,
+    .epilogue = &LoopEpilogue,
+};
+
+}  // namespace
+
+async::Loop* MakeObservableLoop(bool attachToThread) {
+  return new async::Loop(
+      &(attachToThread ? kAttachedLoopConfig : kDetachedLoopConfig));
+}
+
+}  // namespace flutter_runner
diff --git a/shell/platform/fuchsia/flutter/loop.h b/shell/platform/fuchsia/flutter/loop.h
new file mode 100644
index 0000000..02339fe
--- /dev/null
+++ b/shell/platform/fuchsia/flutter/loop.h
@@ -0,0 +1,17 @@
+// Copyright 2013 The Flutter 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 FLUTTER_SHELL_PLATFORM_FUCHSIA_LOOP_H_
+#define FLUTTER_SHELL_PLATFORM_FUCHSIA_LOOP_H_
+
+#include <lib/async-loop/cpp/loop.h>
+
+namespace flutter_runner {
+
+// Creates a loop which allows task observers to be attached to it.
+async::Loop* MakeObservableLoop(bool attachToThread);
+
+}  // namespace flutter_runner
+
+#endif  // FLUTTER_SHELL_PLATFORM_FUCHSIA_LOOP_H_
diff --git a/shell/platform/fuchsia/flutter/main.cc b/shell/platform/fuchsia/flutter/main.cc
index d5bfebb..8f7d0e6 100644
--- a/shell/platform/fuchsia/flutter/main.cc
+++ b/shell/platform/fuchsia/flutter/main.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#define FML_USED_ON_EMBEDDER
-
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/sys/inspect/cpp/component.h>
 #include <lib/trace-provider/provider.h>
@@ -11,8 +9,7 @@
 
 #include <cstdlib>
 
-#include "fml/message_loop.h"
-#include "lib/async/default.h"
+#include "loop.h"
 #include "platform/utils.h"
 #include "runner.h"
 #include "runtime/dart/utils/build_info.h"
@@ -20,7 +17,7 @@
 #include "runtime/dart/utils/tempfs.h"
 
 int main(int argc, char const* argv[]) {
-  fml::MessageLoop::EnsureInitializedForCurrentThread();
+  std::unique_ptr<async::Loop> loop(flutter_runner::MakeObservableLoop(true));
 
   // Create our component context which is served later.
   auto context = sys::ComponentContext::Create();
@@ -38,8 +35,7 @@
     bool already_started;
     // Use CreateSynchronously to prevent loss of early events.
     trace::TraceProviderWithFdio::CreateSynchronously(
-        async_get_default_dispatcher(), "flutter_runner", &provider,
-        &already_started);
+        loop->dispatcher(), "flutter_runner", &provider, &already_started);
   }
 
   // Set up the process-wide /tmp memfs.
@@ -47,13 +43,12 @@
 
   FML_DLOG(INFO) << "Flutter application services initialized.";
 
-  fml::MessageLoop& loop = fml::MessageLoop::GetCurrent();
-  flutter_runner::Runner runner(loop.GetTaskRunner(), context.get());
+  flutter_runner::Runner runner(loop.get(), context.get());
 
   // Wait to serve until we have finished all of our setup.
   context->outgoing()->ServeFromStartupInfo();
 
-  loop.Run();
+  loop->Run();
   FML_DLOG(INFO) << "Flutter application services terminated.";
 
   return EXIT_SUCCESS;
diff --git a/shell/platform/fuchsia/flutter/runner.cc b/shell/platform/fuchsia/flutter/runner.cc
index 86e6dfb..0d10b0b 100644
--- a/shell/platform/fuchsia/flutter/runner.cc
+++ b/shell/platform/fuchsia/flutter/runner.cc
@@ -19,7 +19,6 @@
 #include "flutter/fml/make_copyable.h"
 #include "flutter/lib/ui/text/font_collection.h"
 #include "flutter/runtime/dart_vm.h"
-#include "lib/async/default.h"
 #include "lib/sys/cpp/component_context.h"
 #include "runtime/dart/utils/files.h"
 #include "runtime/dart/utils/root_inspect_node.h"
@@ -149,9 +148,8 @@
 }
 #endif  // !defined(DART_PRODUCT)
 
-Runner::Runner(fml::RefPtr<fml::TaskRunner> task_runner,
-               sys::ComponentContext* context)
-    : task_runner_(task_runner), context_(context) {
+Runner::Runner(async::Loop* loop, sys::ComponentContext* context)
+    : loop_(loop), context_(context) {
 #if !defined(DART_PRODUCT)
   // The VM service isolate uses the process-wide namespace. It writes the
   // vm service protocol port under /tmp. The VMServiceObject exposes that
@@ -234,11 +232,12 @@
   // there being multiple application runner instance in the process at the same
   // time. So it is safe to use the raw pointer.
   Application::TerminationCallback termination_callback =
-      [application_runner = this](const Application* application) {
-        application_runner->task_runner_->PostTask(
-            [application_runner, application]() {
-              application_runner->OnApplicationTerminate(application);
-            });
+      [task_runner = loop_->dispatcher(),  //
+       application_runner = this           //
+  ](const Application* application) {
+        async::PostTask(task_runner, [application_runner, application]() {
+          application_runner->OnApplicationTerminate(application);
+        });
       };
 
   auto active_application = Application::Create(
@@ -267,17 +266,21 @@
   // Grab the items out of the entry because we will have to rethread the
   // destruction.
   auto application_to_destroy = std::move(active_application.application);
-  auto application_thread = std::move(active_application.platform_thread);
+  auto application_thread = std::move(active_application.thread);
 
   // Delegate the entry.
   active_applications_.erase(application);
 
   // Post the task to destroy the application and quit its message loop.
-  application_thread->GetTaskRunner()->PostTask(fml::MakeCopyable(
-      [instance = std::move(application_to_destroy),
-       thread = application_thread.get()]() mutable { instance.reset(); }));
+  async::PostTask(
+      application_thread->dispatcher(),
+      fml::MakeCopyable([instance = std::move(application_to_destroy),
+                         thread = application_thread.get()]() mutable {
+        instance.reset();
+        thread->Quit();
+      }));
 
-  // Terminate and join the thread's message loop.
+  // This works because just posted the quit task on the hosted thread.
   application_thread->Join();
 }
 
@@ -301,36 +304,27 @@
 
 #if !defined(DART_PRODUCT)
 void Runner::SetupTraceObserver() {
-  fml::AutoResetWaitableEvent latch;
-
-  fml::TaskRunner::RunNowOrPostTask(task_runner_, [&]() {
-    // Running this initialization code on task_runner_ ensures that the call to
-    // `async_get_default_dispatcher()` will capture the correct dispatcher.
-    trace_observer_ = std::make_unique<trace::TraceObserver>();
-    trace_observer_->Start(async_get_default_dispatcher(), [runner = this]() {
-      if (!trace_is_category_enabled("dart:profiler")) {
-        return;
+  trace_observer_ = std::make_unique<trace::TraceObserver>();
+  trace_observer_->Start(loop_->dispatcher(), [runner = this]() {
+    if (!trace_is_category_enabled("dart:profiler")) {
+      return;
+    }
+    if (trace_state() == TRACE_STARTED) {
+      runner->prolonged_context_ = trace_acquire_prolonged_context();
+      Dart_StartProfiling();
+    } else if (trace_state() == TRACE_STOPPING) {
+      for (auto& it : runner->active_applications_) {
+        fml::AutoResetWaitableEvent latch;
+        async::PostTask(it.second.thread->dispatcher(), [&]() {
+          it.second.application->WriteProfileToTrace();
+          latch.Signal();
+        });
+        latch.Wait();
       }
-      if (trace_state() == TRACE_STARTED) {
-        runner->prolonged_context_ = trace_acquire_prolonged_context();
-        Dart_StartProfiling();
-      } else if (trace_state() == TRACE_STOPPING) {
-        for (auto& it : runner->active_applications_) {
-          fml::AutoResetWaitableEvent latch;
-          fml::TaskRunner::RunNowOrPostTask(
-              it.second.platform_thread->GetTaskRunner(), [&]() {
-                it.second.application->WriteProfileToTrace();
-                latch.Signal();
-              });
-          latch.Wait();
-        }
-        Dart_StopProfiling();
-        trace_release_prolonged_context(runner->prolonged_context_);
-      }
-    });
-    latch.Signal();
+      Dart_StopProfiling();
+      trace_release_prolonged_context(runner->prolonged_context_);
+    }
   });
-  latch.Wait();
 }
 #endif  // !defined(DART_PRODUCT)
 
diff --git a/shell/platform/fuchsia/flutter/runner.h b/shell/platform/fuchsia/flutter/runner.h
index ccd7614..0290275 100644
--- a/shell/platform/fuchsia/flutter/runner.h
+++ b/shell/platform/fuchsia/flutter/runner.h
@@ -16,8 +16,6 @@
 
 #include "component.h"
 #include "flutter/fml/macros.h"
-#include "fml/memory/ref_ptr.h"
-#include "fml/task_runner.h"
 #include "lib/fidl/cpp/binding_set.h"
 #include "runtime/dart/utils/vmservice_object.h"
 
@@ -27,14 +25,13 @@
 // their own threads.
 class Runner final : public fuchsia::sys::Runner {
  public:
-  // Does not take ownership of context.
-  Runner(fml::RefPtr<fml::TaskRunner> task_runner,
-         sys::ComponentContext* context);
+  // Does not take ownership of loop or context.
+  Runner(async::Loop* loop, sys::ComponentContext* context);
 
   ~Runner();
 
  private:
-  fml::RefPtr<fml::TaskRunner> task_runner_;
+  async::Loop* loop_;
 
   sys::ComponentContext* context_;
   fidl::BindingSet<fuchsia::sys::Runner> active_applications_bindings_;
diff --git a/fml/platform/fuchsia/task_observers.cc b/shell/platform/fuchsia/flutter/task_observers.cc
similarity index 87%
rename from fml/platform/fuchsia/task_observers.cc
rename to shell/platform/fuchsia/flutter/task_observers.cc
index d3a9ea1..7a62368 100644
--- a/fml/platform/fuchsia/task_observers.cc
+++ b/shell/platform/fuchsia/flutter/task_observers.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "flutter/fml/platform/fuchsia/task_observers.h"
+#include "task_observers.h"
 
 #include <map>
 
-namespace fml {
+namespace flutter_runner {
 
 thread_local std::map<intptr_t, fit::closure> tTaskObservers;
 
@@ -27,4 +27,4 @@
   tTaskObservers.erase(key);
 }
 
-}  // namespace fml
+}  // namespace flutter_runner
diff --git a/shell/platform/fuchsia/flutter/task_observers.h b/shell/platform/fuchsia/flutter/task_observers.h
new file mode 100644
index 0000000..5ee27d7
--- /dev/null
+++ b/shell/platform/fuchsia/flutter/task_observers.h
@@ -0,0 +1,21 @@
+// Copyright 2013 The Flutter 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 FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_
+#define FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_
+
+#include <lib/fit/function.h>
+
+namespace flutter_runner {
+
+void ExecuteAfterTaskObservers();
+
+void CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
+                                            fit::closure observer);
+
+void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key);
+
+}  // namespace flutter_runner
+
+#endif  // FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_
diff --git a/shell/platform/fuchsia/flutter/thread.cc b/shell/platform/fuchsia/flutter/thread.cc
new file mode 100644
index 0000000..c0c68e8
--- /dev/null
+++ b/shell/platform/fuchsia/flutter/thread.cc
@@ -0,0 +1,102 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "thread.h"
+
+#include <lib/async-loop/cpp/loop.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <climits>
+
+#include "flutter/fml/logging.h"
+#include "loop.h"
+
+namespace flutter_runner {
+
+typedef void (*ThreadEntry)(Thread*);
+
+namespace {
+
+size_t NextPageSizeMultiple(size_t size) {
+  const size_t page_size = sysconf(_SC_PAGE_SIZE);
+  FML_CHECK(page_size != 0);
+
+  size = std::max<size_t>(size, page_size);
+
+  size_t rem = size % page_size;
+
+  if (rem == 0) {
+    return size;
+  }
+
+  return size + page_size - rem;
+}
+
+bool CreateThread(pthread_t* thread,
+                  ThreadEntry main,
+                  Thread* argument,
+                  size_t stack_size) {
+  pthread_attr_t thread_attributes;
+
+  if (pthread_attr_init(&thread_attributes) != 0) {
+    return false;
+  }
+
+  stack_size = std::max<size_t>(NextPageSizeMultiple(PTHREAD_STACK_MIN),
+                                NextPageSizeMultiple(stack_size));
+
+  if (pthread_attr_setstacksize(&thread_attributes, stack_size) != 0) {
+    return false;
+  }
+
+  auto result =
+      pthread_create(thread, &thread_attributes,
+                     reinterpret_cast<void* (*)(void*)>(main), argument);
+
+  pthread_attr_destroy(&thread_attributes);
+
+  return result == 0;
+}
+
+}  // anonymous namespace
+
+Thread::Thread() {
+  loop_.reset(MakeObservableLoop(false));
+  valid_ = CreateThread(
+      &thread_, [](Thread* thread) { thread->Main(); }, this, 1 << 20);
+}
+
+Thread::~Thread() {
+  Join();
+}
+
+bool Thread::IsValid() const {
+  return valid_;
+}
+
+async_dispatcher_t* Thread::dispatcher() const {
+  return loop_->dispatcher();
+}
+
+void Thread::Main() {
+  async_set_default_dispatcher(loop_->dispatcher());
+  loop_->Run();
+}
+
+void Thread::Quit() {
+  loop_->Quit();
+}
+
+bool Thread::Join() {
+  if (!valid_) {
+    return false;
+  }
+
+  bool result = pthread_join(thread_, nullptr) == 0;
+  valid_ = false;
+  return result;
+}
+
+}  // namespace flutter_runner
diff --git a/shell/platform/fuchsia/flutter/thread.h b/shell/platform/fuchsia/flutter/thread.h
new file mode 100644
index 0000000..ace85c3
--- /dev/null
+++ b/shell/platform/fuchsia/flutter/thread.h
@@ -0,0 +1,44 @@
+// Copyright 2013 The Flutter 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 FLUTTER_SHELL_PLATFORM_FUCHSIA_THREAD_H_
+#define FLUTTER_SHELL_PLATFORM_FUCHSIA_THREAD_H_
+
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async/default.h>
+#include <pthread.h>
+
+#include <functional>
+
+#include "flutter/fml/macros.h"
+
+namespace flutter_runner {
+
+class Thread {
+ public:
+  Thread();
+
+  ~Thread();
+
+  void Quit();
+
+  bool Join();
+
+  bool IsValid() const;
+
+  async_dispatcher_t* dispatcher() const;
+
+ private:
+  bool valid_;
+  pthread_t thread_;
+  std::unique_ptr<async::Loop> loop_;
+
+  void Main();
+
+  FML_DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+}  // namespace flutter_runner
+
+#endif  // FLUTTER_SHELL_PLATFORM_FUCHSIA_THREAD_H_