[engine] force semantics action to post a task. (#56514)

Repro:

Testing WIP.

b/373761573

```dart

import 'package:flutter/material.dart';

void main() {
  runApp(const Example());
}

class Example extends StatefulWidget {
  const Example({super.key});

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  bool value = true;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Semantics(
            child: Text(
              value ? 'Hello, world!' : 'Goodbye, World!',
            ),
            button: true,
            onTap: () async {
              await null;
              setState(() {
                value = !value;
              });
            },
          ),
        ),
      ),
      );
  }
}

```
diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart
index 9826d58..6072756 100644
--- a/shell/common/fixtures/shell_test.dart
+++ b/shell/common/fixtures/shell_test.dart
@@ -4,6 +4,7 @@
 
 // ignore_for_file: avoid_print
 
+import 'dart:async';
 import 'dart:convert' show json, utf8;
 import 'dart:isolate';
 import 'dart:typed_data';
@@ -629,3 +630,13 @@
     }
   });
 }
+
+@pragma('vm:entry-point')
+void testSemanticsActions() {
+  PlatformDispatcher.instance.onSemanticsActionEvent = (SemanticsActionEvent action) async {
+    await null;
+    Future<void>.value().then((_) {
+      notifyNative();
+    });
+  };
+}
diff --git a/shell/common/shell.cc b/shell/common/shell.cc
index 6077979..c6078f7 100644
--- a/shell/common/shell.cc
+++ b/shell/common/shell.cc
@@ -1122,8 +1122,7 @@
   FML_DCHECK(is_set_up_);
   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
 
-  fml::TaskRunner::RunNowOrPostTask(
-      task_runners_.GetUITaskRunner(),
+  task_runners_.GetUITaskRunner()->PostTask(
       fml::MakeCopyable([engine = engine_->GetWeakPtr(), node_id, action,
                          args = std::move(args)]() mutable {
         if (engine) {
diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc
index 48a18b8..800d3d1 100644
--- a/shell/common/shell_test.cc
+++ b/shell/common/shell_test.cc
@@ -65,6 +65,14 @@
   shell->OnPlatformViewDispatchPlatformMessage(std::move(message));
 }
 
+void ShellTest::SendSemanticsAction(Shell* shell,
+                                    int32_t node_id,
+                                    SemanticsAction action,
+                                    fml::MallocMapping args) {
+  shell->OnPlatformViewDispatchSemanticsAction(node_id, action,
+                                               std::move(args));
+}
+
 void ShellTest::SendEnginePlatformMessage(
     Shell* shell,
     std::unique_ptr<PlatformMessage> message) {
diff --git a/shell/common/shell_test.h b/shell/common/shell_test.h
index 4fb758e..e980474 100644
--- a/shell/common/shell_test.h
+++ b/shell/common/shell_test.h
@@ -90,6 +90,11 @@
   void SendPlatformMessage(Shell* shell,
                            std::unique_ptr<PlatformMessage> message);
 
+  void SendSemanticsAction(Shell* shell,
+                           int32_t node_id,
+                           SemanticsAction action,
+                           fml::MallocMapping args);
+
   void SendEnginePlatformMessage(Shell* shell,
                                  std::unique_ptr<PlatformMessage> message);
 
diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc
index 2149c25..1875eac 100644
--- a/shell/common/shell_unittests.cc
+++ b/shell/common/shell_unittests.cc
@@ -45,8 +45,10 @@
 #include "flutter/shell/common/vsync_waiters_test.h"
 #include "flutter/shell/version/version.h"
 #include "flutter/testing/testing.h"
+#include "fml/mapping.h"
 #include "gmock/gmock.h"
 #include "impeller/core/runtime_types.h"
+#include "lib/ui/semantics/semantics_node.h"
 #include "third_party/rapidjson/include/rapidjson/writer.h"
 #include "third_party/skia/include/codec/SkCodecAnimation.h"
 #include "third_party/tonic/converter/dart_converter.h"
@@ -4311,6 +4313,41 @@
   ASSERT_FALSE(DartVMRef::IsInstanceRunning());
 }
 
+TEST_F(ShellTest, SemanticsActionsPostTask) {
+  Settings settings = CreateSettingsForFixture();
+  ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
+                         ThreadHost::Type::kPlatform);
+  auto task_runner = thread_host.platform_thread->GetTaskRunner();
+  TaskRunners task_runners("test", task_runner, task_runner, task_runner,
+                           task_runner);
+
+  EXPECT_EQ(task_runners.GetPlatformTaskRunner(),
+            task_runners.GetUITaskRunner());
+  auto shell = CreateShell(settings, task_runners);
+  auto configuration = RunConfiguration::InferFromSettings(settings);
+  configuration.SetEntrypoint("testSemanticsActions");
+
+  RunEngine(shell.get(), std::move(configuration));
+
+  task_runners.GetPlatformTaskRunner()->PostTask([&] {
+    SendSemanticsAction(shell.get(), 0, SemanticsAction::kTap,
+                        fml::MallocMapping(nullptr, 0));
+  });
+
+  // Fulfill native function for the second Shell's entrypoint.
+  fml::CountDownLatch latch(1);
+  AddNativeCallback(
+      // The Dart native function names aren't very consistent but this is
+      // just the native function name of the second vm entrypoint in the
+      // fixture.
+      "NotifyNative",
+      CREATE_NATIVE_ENTRY([&](auto args) { latch.CountDown(); }));
+  latch.Wait();
+
+  DestroyShell(std::move(shell), task_runners);
+  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
+}
+
 TEST_F(ShellTest, DiesIfSoftwareRenderingAndImpellerAreEnabledDeathTest) {
 #if defined(OS_FUCHSIA)
   GTEST_SKIP() << "Fuchsia";