added trace events for scheduling responses to platform messages (#34230)

diff --git a/lib/ui/ui_benchmarks.cc b/lib/ui/ui_benchmarks.cc
index 4c8239b..ce1d4c6 100644
--- a/lib/ui/ui_benchmarks.cc
+++ b/lib/ui/ui_benchmarks.cc
@@ -48,7 +48,7 @@
 
       auto message = fml::MakeRefCounted<PlatformMessageResponseDart>(
           tonic::DartPersistentValue(isolate->get(), closure),
-          thread_host.ui_thread->GetTaskRunner());
+          thread_host.ui_thread->GetTaskRunner(), "");
 
       message->Complete(std::move(mapping));
 
diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc
index 3914578..bee2f79 100644
--- a/lib/ui/window/platform_configuration.cc
+++ b/lib/ui/window/platform_configuration.cc
@@ -97,7 +97,7 @@
   if (!Dart_IsNull(callback)) {
     response = fml::MakeRefCounted<PlatformMessageResponseDart>(
         tonic::DartPersistentValue(dart_state, callback),
-        dart_state->GetTaskRunners().GetUITaskRunner());
+        dart_state->GetTaskRunners().GetUITaskRunner(), name);
   }
   if (Dart_IsNull(data_handle)) {
     dart_state->platform_configuration()->client()->HandlePlatformMessage(
diff --git a/lib/ui/window/platform_message_response_dart.cc b/lib/ui/window/platform_message_response_dart.cc
index f53fc41..39d55f4 100644
--- a/lib/ui/window/platform_message_response_dart.cc
+++ b/lib/ui/window/platform_message_response_dart.cc
@@ -8,17 +8,52 @@
 
 #include "flutter/common/task_runners.h"
 #include "flutter/fml/make_copyable.h"
+#include "flutter/fml/trace_event.h"
 #include "third_party/tonic/dart_state.h"
 #include "third_party/tonic/logging/dart_invoke.h"
 #include "third_party/tonic/typed_data/dart_byte_data.h"
 
+static std::atomic<uint64_t> platform_message_counter = 1;
+
 namespace flutter {
+namespace {
+template <typename Callback, typename TaskRunner, typename Result>
+void PostCompletion(Callback&& callback,
+                    const TaskRunner& ui_task_runner,
+                    bool* is_complete,
+                    const std::string& channel,
+                    Result&& result) {
+  if (callback.is_empty()) {
+    return;
+  }
+  FML_DCHECK(!*is_complete);
+  *is_complete = true;
+  uint64_t platform_message_id = platform_message_counter.fetch_add(1);
+  TRACE_EVENT_ASYNC_BEGIN1("flutter", "PlatformChannel ScheduleResult",
+                           platform_message_id, "channel", channel.c_str());
+  ui_task_runner->PostTask(fml::MakeCopyable(
+      [callback = std::move(callback), platform_message_id,
+       result = std::move(result), channel = channel]() mutable {
+        TRACE_EVENT_ASYNC_END0("flutter", "PlatformChannel ScheduleResult",
+                               platform_message_id);
+        std::shared_ptr<tonic::DartState> dart_state =
+            callback.dart_state().lock();
+        if (!dart_state) {
+          return;
+        }
+        tonic::DartState::Scope scope(dart_state);
+        tonic::DartInvoke(callback.Release(), {result()});
+      }));
+}
+}  // namespace
 
 PlatformMessageResponseDart::PlatformMessageResponseDart(
     tonic::DartPersistentValue callback,
-    fml::RefPtr<fml::TaskRunner> ui_task_runner)
+    fml::RefPtr<fml::TaskRunner> ui_task_runner,
+    const std::string& channel)
     : callback_(std::move(callback)),
-      ui_task_runner_(std::move(ui_task_runner)) {}
+      ui_task_runner_(std::move(ui_task_runner)),
+      channel_(channel) {}
 
 PlatformMessageResponseDart::~PlatformMessageResponseDart() {
   if (!callback_.is_empty()) {
@@ -28,42 +63,16 @@
 }
 
 void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
-  if (callback_.is_empty()) {
-    return;
-  }
-  FML_DCHECK(!is_complete_);
-  is_complete_ = true;
-  ui_task_runner_->PostTask(fml::MakeCopyable(
-      [callback = std::move(callback_), data = std::move(data)]() mutable {
-        std::shared_ptr<tonic::DartState> dart_state =
-            callback.dart_state().lock();
-        if (!dart_state) {
-          return;
-        }
-        tonic::DartState::Scope scope(dart_state);
-
-        Dart_Handle byte_buffer =
-            tonic::DartByteData::Create(data->GetMapping(), data->GetSize());
-        tonic::DartInvoke(callback.Release(), {byte_buffer});
-      }));
+  PostCompletion(std::move(callback_), ui_task_runner_, &is_complete_, channel_,
+                 [data = std::move(data)] {
+                   return tonic::DartByteData::Create(data->GetMapping(),
+                                                      data->GetSize());
+                 });
 }
 
 void PlatformMessageResponseDart::CompleteEmpty() {
-  if (callback_.is_empty()) {
-    return;
-  }
-  FML_DCHECK(!is_complete_);
-  is_complete_ = true;
-  ui_task_runner_->PostTask(
-      fml::MakeCopyable([callback = std::move(callback_)]() mutable {
-        std::shared_ptr<tonic::DartState> dart_state =
-            callback.dart_state().lock();
-        if (!dart_state) {
-          return;
-        }
-        tonic::DartState::Scope scope(dart_state);
-        tonic::DartInvoke(callback.Release(), {Dart_Null()});
-      }));
+  PostCompletion(std::move(callback_), ui_task_runner_, &is_complete_, channel_,
+                 [] { return Dart_Null(); });
 }
 
 }  // namespace flutter
diff --git a/lib/ui/window/platform_message_response_dart.h b/lib/ui/window/platform_message_response_dart.h
index 79293ff..f290faf 100644
--- a/lib/ui/window/platform_message_response_dart.h
+++ b/lib/ui/window/platform_message_response_dart.h
@@ -22,11 +22,13 @@
  protected:
   explicit PlatformMessageResponseDart(
       tonic::DartPersistentValue callback,
-      fml::RefPtr<fml::TaskRunner> ui_task_runner);
+      fml::RefPtr<fml::TaskRunner> ui_task_runner,
+      const std::string& channel);
   ~PlatformMessageResponseDart() override;
 
   tonic::DartPersistentValue callback_;
   fml::RefPtr<fml::TaskRunner> ui_task_runner_;
+  const std::string channel_;
 };
 
 }  // namespace flutter
diff --git a/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java b/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java
index d97b730..8a90964 100644
--- a/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java
+++ b/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java
@@ -312,8 +312,10 @@
       int replyId,
       long messageData) {
     final DartMessengerTaskQueue taskQueue = (handlerInfo != null) ? handlerInfo.taskQueue : null;
+    TraceSection.beginAsyncSection("PlatformChannel ScheduleHandler on " + channel, replyId);
     Runnable myRunnable =
         () -> {
+          TraceSection.endAsyncSection("PlatformChannel ScheduleHandler on " + channel, replyId);
           TraceSection.begin("DartMessenger#handleMessageFromDart on " + channel);
           try {
             invokeHandler(handlerInfo, message, replyId);
diff --git a/shell/platform/android/io/flutter/util/TraceSection.java b/shell/platform/android/io/flutter/util/TraceSection.java
index 0f61864..53c2889 100644
--- a/shell/platform/android/io/flutter/util/TraceSection.java
+++ b/shell/platform/android/io/flutter/util/TraceSection.java
@@ -8,18 +8,36 @@
 import androidx.tracing.Trace;
 
 public final class TraceSection {
+  private static String cropSectionName(@NonNull String sectionName) {
+    return sectionName.length() < 124 ? sectionName : sectionName.substring(0, 124) + "...";
+  }
+
   /**
    * Wraps Trace.beginSection to ensure that the line length stays below 127 code units.
    *
    * @param sectionName The string to display as the section name in the trace.
    */
   public static void begin(@NonNull String sectionName) {
-    sectionName = sectionName.length() < 124 ? sectionName : sectionName.substring(0, 124) + "...";
-    Trace.beginSection(sectionName);
+    Trace.beginSection(cropSectionName(sectionName));
   }
 
   /** Wraps Trace.endSection. */
   public static void end() throws RuntimeException {
     Trace.endSection();
   }
+
+  /**
+   * Wraps Trace.beginAsyncSection to ensure that the line length stays below 127 code units.
+   *
+   * @param sectionName The string to display as the section name in the trace.
+   * @param cookie Unique integer defining the section.
+   */
+  public static void beginAsyncSection(String sectionName, int cookie) {
+    Trace.beginAsyncSection(cropSectionName(sectionName), cookie);
+  }
+
+  /** Wraps Trace.endAsyncSection to ensure that the line length stays below 127 code units. */
+  public static void endAsyncSection(String sectionName, int cookie) {
+    Trace.endAsyncSection(cropSectionName(sectionName), cookie);
+  }
 }
diff --git a/shell/platform/darwin/ios/platform_message_handler_ios.mm b/shell/platform/darwin/ios/platform_message_handler_ios.mm
index 9e316cc..7f6efcd6 100644
--- a/shell/platform/darwin/ios/platform_message_handler_ios.mm
+++ b/shell/platform/darwin/ios/platform_message_handler_ios.mm
@@ -4,9 +4,12 @@
 
 #import "flutter/shell/platform/darwin/ios/platform_message_handler_ios.h"
 
+#import "flutter/fml/trace_event.h"
 #import "flutter/shell/platform/darwin/common/buffer_conversions.h"
 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
 
+static uint64_t platform_message_counter = 1;
+
 @protocol FlutterTaskQueue
 - (void)dispatch:(dispatch_block_t)block;
 @end
@@ -61,8 +64,12 @@
       data = ConvertMappingToNSData(message->releaseData());
     }
 
+    uint64_t platform_message_id = platform_message_counter++;
+    TRACE_EVENT_ASYNC_BEGIN1("flutter", "PlatformChannel ScheduleHandler", platform_message_id,
+                             "channel", message->channel().c_str());
     dispatch_block_t run_handler = ^{
       handler(data, ^(NSData* reply) {
+        TRACE_EVENT_ASYNC_END0("flutter", "PlatformChannel ScheduleHandler", platform_message_id);
         // Called from any thread.
         if (completer) {
           if (reply) {