Update the observatory thread name for profiling thread (#18199)

diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
index f9b70ba..c162e67 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
@@ -325,10 +325,10 @@
   _settingsChannel.reset();
 }
 
-- (void)startProfiler {
+- (void)startProfiler:(NSString*)threadLabel {
   _profiler_metrics = std::make_unique<flutter::ProfilerMetricsIOS>();
   _profiler = std::make_unique<flutter::SamplingProfiler>(
-      _threadHost.profiler_thread->GetTaskRunner(),
+      threadLabel.UTF8String, _threadHost.profiler_thread->GetTaskRunner(),
       [self]() { return self->_profiler_metrics->GenerateSample(); }, kNumProfilerSamplesPerSec);
   _profiler->Start();
 }
@@ -478,10 +478,6 @@
         return std::make_unique<flutter::Rasterizer>(shell, shell.GetTaskRunners());
       };
 
-  if (profilerEnabled) {
-    [self startProfiler];
-  }
-
   if (flutter::IsIosEmbeddedViewsPreviewEnabled()) {
     // Embedded views requires the gpu and the platform views to be the same.
     // The plan is to eventually dynamically merge the threads when there's a
@@ -532,6 +528,9 @@
     _publisher.reset([[FlutterObservatoryPublisher alloc] init]);
     [self maybeSetupPlatformViewChannels];
     _shell->GetIsGpuDisabledSyncSwitch()->SetSwitch(_isGpuDisabled ? true : false);
+    if (profilerEnabled) {
+      [self startProfiler:threadLabel];
+    }
   }
 
   return _shell != nullptr;
diff --git a/shell/profiling/sampling_profiler.cc b/shell/profiling/sampling_profiler.cc
index 6bdd435..46844da 100644
--- a/shell/profiling/sampling_profiler.cc
+++ b/shell/profiling/sampling_profiler.cc
@@ -7,10 +7,12 @@
 namespace flutter {
 
 SamplingProfiler::SamplingProfiler(
+    const char* thread_label,
     fml::RefPtr<fml::TaskRunner> profiler_task_runner,
     Sampler sampler,
     int num_samples_per_sec)
-    : profiler_task_runner_(profiler_task_runner),
+    : thread_label_(thread_label),
+      profiler_task_runner_(profiler_task_runner),
       sampler_(std::move(sampler)),
       num_samples_per_sec_(num_samples_per_sec) {}
 
@@ -23,6 +25,7 @@
       << num_samples_per_sec_;
   double delay_between_samples = 1.0 / num_samples_per_sec_;
   auto task_delay = fml::TimeDelta::FromSecondsF(delay_between_samples);
+  UpdateObservatoryThreadName();
   SampleRepeatedly(task_delay);
 }
 
@@ -46,4 +49,13 @@
       task_delay);
 }
 
+void SamplingProfiler::UpdateObservatoryThreadName() const {
+  FML_CHECK(profiler_task_runner_);
+
+  profiler_task_runner_->PostTask(
+      [label = thread_label_ + std::string{".profiler"}]() {
+        Dart_SetThreadName(label.c_str());
+      });
+}
+
 }  // namespace flutter
diff --git a/shell/profiling/sampling_profiler.h b/shell/profiling/sampling_profiler.h
index be8465d..76917ab 100644
--- a/shell/profiling/sampling_profiler.h
+++ b/shell/profiling/sampling_profiler.h
@@ -8,6 +8,7 @@
 #include <functional>
 #include <memory>
 #include <optional>
+#include <string>
 
 #include "flutter/fml/task_runner.h"
 #include "flutter/fml/trace_event.h"
@@ -60,6 +61,8 @@
   /**
    * @brief Construct a new Sampling Profiler object
    *
+   * @param thread_label observatory prefix to be set for the profiling task
+   * runner.
    * @param profiler_task_runner the task runner to service sampling requests.
    * @param sampler the value function to collect the profiling metrics.
    * @param num_samples_per_sec number of times you wish to run the sampler per
@@ -67,7 +70,8 @@
    *
    * @see fml::TaskRunner
    */
-  SamplingProfiler(fml::RefPtr<fml::TaskRunner> profiler_task_runner,
+  SamplingProfiler(const char* thread_label,
+                   fml::RefPtr<fml::TaskRunner> profiler_task_runner,
                    Sampler sampler,
                    int num_samples_per_sec);
 
@@ -78,12 +82,21 @@
   void Start() const;
 
  private:
+  const std::string thread_label_;
   const fml::RefPtr<fml::TaskRunner> profiler_task_runner_;
   const Sampler sampler_;
   const uint32_t num_samples_per_sec_;
 
   void SampleRepeatedly(fml::TimeDelta task_delay) const;
 
+  /**
+   * @brief This doesn't update the underlying OS thread name for the thread
+   * backing `profiler_task_runner_`. Instead, this is just additional metadata
+   * for the Observatory to show the thread name of the isolate.
+   *
+   */
+  void UpdateObservatoryThreadName() const;
+
   FML_DISALLOW_COPY_AND_ASSIGN(SamplingProfiler);
 };
 
diff --git a/testing/ios/IosUnitTests/build_and_run_tests.sh b/testing/ios/IosUnitTests/build_and_run_tests.sh
index 787a969..072911e 100755
--- a/testing/ios/IosUnitTests/build_and_run_tests.sh
+++ b/testing/ios/IosUnitTests/build_and_run_tests.sh
@@ -21,4 +21,4 @@
 
 autoninja -C out/$FLUTTER_ENGINE ios_test_flutter
 popd
-./run_tests.sh $FLUTTER_ENGINE
+$TESTING_DIR/run_tests.sh $FLUTTER_ENGINE
diff --git a/testing/ios/IosUnitTests/run_tests.sh b/testing/ios/IosUnitTests/run_tests.sh
index 178f7d4..3ce96a0 100755
--- a/testing/ios/IosUnitTests/run_tests.sh
+++ b/testing/ios/IosUnitTests/run_tests.sh
@@ -15,7 +15,7 @@
 
 set -o pipefail && xcodebuild -sdk iphonesimulator \
   -scheme IosUnitTests \
-  -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.0' \
+  -destination 'platform=iOS Simulator,name=iPhone 8' \
   test \
   FLUTTER_ENGINE=$FLUTTER_ENGINE | $PRETTY