Turned back on debug unit tests (#42261)

I refactored the `EXPECT_EXIT` tests since they are unsafe to execute in a process with multiple threads.

This leaves `flutter_desktop_darwin_unittests` disabled since it has existing issues.

fixes https://github.com/flutter/flutter/issues/103757

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json
index 6b9c9c5..21d80f8 100644
--- a/ci/builders/mac_host_engine.json
+++ b/ci/builders/mac_host_engine.json
@@ -51,7 +51,7 @@
                         "--variant",
                         "host_debug",
                         "--type",
-                        "dart",
+                        "dart,engine",
                         "--engine-capture-core-dump"
                     ],
                     "script": "flutter/testing/run_tests.py"
diff --git a/flow/frame_timings.cc b/flow/frame_timings.cc
index 7b5c0f9..eed35fd 100644
--- a/flow/frame_timings.cc
+++ b/flow/frame_timings.cc
@@ -103,32 +103,75 @@
 
 void FrameTimingsRecorder::RecordVsync(fml::TimePoint vsync_start,
                                        fml::TimePoint vsync_target) {
-  std::scoped_lock state_lock(state_mutex_);
-  FML_DCHECK(state_ == State::kUninitialized);
-  state_ = State::kVsync;
-  vsync_start_ = vsync_start;
-  vsync_target_ = vsync_target;
+  fml::Status status = RecordVsyncImpl(vsync_start, vsync_target);
+  FML_DCHECK(status.ok());
+  (void)status;
 }
 
 void FrameTimingsRecorder::RecordBuildStart(fml::TimePoint build_start) {
-  std::scoped_lock state_lock(state_mutex_);
-  FML_DCHECK(state_ == State::kVsync);
-  state_ = State::kBuildStart;
-  build_start_ = build_start;
+  fml::Status status = RecordBuildStartImpl(build_start);
+  FML_DCHECK(status.ok());
+  (void)status;
 }
 
 void FrameTimingsRecorder::RecordBuildEnd(fml::TimePoint build_end) {
-  std::scoped_lock state_lock(state_mutex_);
-  FML_DCHECK(state_ == State::kBuildStart);
-  state_ = State::kBuildEnd;
-  build_end_ = build_end;
+  fml::Status status = RecordBuildEndImpl(build_end);
+  FML_DCHECK(status.ok());
+  (void)status;
 }
 
 void FrameTimingsRecorder::RecordRasterStart(fml::TimePoint raster_start) {
+  fml::Status status = RecordRasterStartImpl(raster_start);
+  FML_DCHECK(status.ok());
+  (void)status;
+}
+
+fml::Status FrameTimingsRecorder::RecordVsyncImpl(fml::TimePoint vsync_start,
+                                                  fml::TimePoint vsync_target) {
   std::scoped_lock state_lock(state_mutex_);
-  FML_DCHECK(state_ == State::kBuildEnd);
+  if (state_ != State::kUninitialized) {
+    return fml::Status(fml::StatusCode::kFailedPrecondition,
+                       "Check failed: state_ == State::kUninitialized.");
+  }
+  state_ = State::kVsync;
+  vsync_start_ = vsync_start;
+  vsync_target_ = vsync_target;
+  return fml::Status();
+}
+
+fml::Status FrameTimingsRecorder::RecordBuildStartImpl(
+    fml::TimePoint build_start) {
+  std::scoped_lock state_lock(state_mutex_);
+  if (state_ != State::kVsync) {
+    return fml::Status(fml::StatusCode::kFailedPrecondition,
+                       "Check failed: state_ == State::kVsync.");
+  }
+  state_ = State::kBuildStart;
+  build_start_ = build_start;
+  return fml::Status();
+}
+
+fml::Status FrameTimingsRecorder::RecordBuildEndImpl(fml::TimePoint build_end) {
+  std::scoped_lock state_lock(state_mutex_);
+  if (state_ != State::kBuildStart) {
+    return fml::Status(fml::StatusCode::kFailedPrecondition,
+                       "Check failed: state_ == State::kBuildStart.");
+  }
+  state_ = State::kBuildEnd;
+  build_end_ = build_end;
+  return fml::Status();
+}
+
+fml::Status FrameTimingsRecorder::RecordRasterStartImpl(
+    fml::TimePoint raster_start) {
+  std::scoped_lock state_lock(state_mutex_);
+  if (state_ != State::kBuildEnd) {
+    return fml::Status(fml::StatusCode::kFailedPrecondition,
+                       "Check failed: state_ == State::kBuildEnd.");
+  }
   state_ = State::kRasterStart;
   raster_start_ = raster_start;
+  return fml::Status();
 }
 
 FrameTiming FrameTimingsRecorder::RecordRasterEnd(const RasterCache* cache) {
diff --git a/flow/frame_timings.h b/flow/frame_timings.h
index 8d39bb6..76b9281 100644
--- a/flow/frame_timings.h
+++ b/flow/frame_timings.h
@@ -10,6 +10,7 @@
 #include "flutter/common/settings.h"
 #include "flutter/flow/raster_cache.h"
 #include "flutter/fml/macros.h"
+#include "flutter/fml/status.h"
 #include "flutter/fml/time/time_delta.h"
 #include "flutter/fml/time/time_point.h"
 
@@ -114,6 +115,16 @@
   FrameTiming GetRecordedTime() const;
 
  private:
+  FML_FRIEND_TEST(FrameTimingsRecorderTest, ThrowWhenRecordBuildBeforeVsync);
+  FML_FRIEND_TEST(FrameTimingsRecorderTest,
+                  ThrowWhenRecordRasterBeforeBuildEnd);
+
+  [[nodiscard]] fml::Status RecordVsyncImpl(fml::TimePoint vsync_start,
+                                            fml::TimePoint vsync_target);
+  [[nodiscard]] fml::Status RecordBuildStartImpl(fml::TimePoint build_start);
+  [[nodiscard]] fml::Status RecordBuildEndImpl(fml::TimePoint build_end);
+  [[nodiscard]] fml::Status RecordRasterStartImpl(fml::TimePoint raster_start);
+
   static std::atomic<uint64_t> frame_number_gen_;
 
   mutable std::mutex state_mutex_;
diff --git a/flow/frame_timings_recorder_unittests.cc b/flow/frame_timings_recorder_unittests.cc
index ab1ef1e..db3896c 100644
--- a/flow/frame_timings_recorder_unittests.cc
+++ b/flow/frame_timings_recorder_unittests.cc
@@ -2,21 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <thread>
 #include "flutter/flow/frame_timings.h"
 #include "flutter/flow/testing/layer_test.h"
 #include "flutter/flow/testing/mock_layer.h"
 #include "flutter/flow/testing/mock_raster_cache.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
 
-#include <thread>
-
 #include "flutter/fml/time/time_delta.h"
 #include "flutter/fml/time/time_point.h"
 
 #include "gtest/gtest.h"
 
 namespace flutter {
-namespace testing {
+
+using testing::MockRasterCache;
 
 TEST(FrameTimingsRecorderTest, RecordVsync) {
   auto recorder = std::make_unique<FrameTimingsRecorder>();
@@ -130,9 +130,9 @@
   auto recorder = std::make_unique<FrameTimingsRecorder>();
 
   const auto build_start = fml::TimePoint::Now();
-  EXPECT_EXIT(recorder->RecordBuildStart(build_start),
-              ::testing::KilledBySignal(SIGABRT),
-              "Check failed: state_ == State::kVsync.");
+  fml::Status status = recorder->RecordBuildStartImpl(build_start);
+  EXPECT_FALSE(status.ok());
+  EXPECT_EQ(status.message(), "Check failed: state_ == State::kVsync.");
 }
 
 TEST(FrameTimingsRecorderTest, ThrowWhenRecordRasterBeforeBuildEnd) {
@@ -143,9 +143,9 @@
   recorder->RecordVsync(st, en);
 
   const auto raster_start = fml::TimePoint::Now();
-  EXPECT_EXIT(recorder->RecordRasterStart(raster_start),
-              ::testing::KilledBySignal(SIGABRT),
-              "Check failed: state_ == State::kBuildEnd.");
+  fml::Status status = recorder->RecordRasterStartImpl(raster_start);
+  EXPECT_FALSE(status.ok());
+  EXPECT_EQ(status.message(), "Check failed: state_ == State::kBuildEnd.");
 }
 
 #endif
@@ -297,5 +297,4 @@
   ASSERT_EQ(actual_arg, expected_arg);
 }
 
-}  // namespace testing
 }  // namespace flutter
diff --git a/fml/macros.h b/fml/macros.h
index 0158d0e..7de4ddf 100644
--- a/fml/macros.h
+++ b/fml/macros.h
@@ -38,4 +38,7 @@
   TypeName() = delete;                               \
   FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TypeName)
 
+#define FML_FRIEND_TEST(test_case_name, test_name) \
+  friend class test_case_name##_##test_name##_Test
+
 #endif  // FLUTTER_FML_MACROS_H_
diff --git a/testing/run_tests.py b/testing/run_tests.py
index 74ea48c..8fcf8b30 100755
--- a/testing/run_tests.py
+++ b/testing/run_tests.py
@@ -471,13 +471,16 @@
     # flutter_desktop_darwin_unittests uses global state that isn't handled
     # correctly by gtest-parallel.
     # https://github.com/flutter/flutter/issues/104789
-    run_engine_executable(
-        build_dir,
-        'flutter_desktop_darwin_unittests',
-        executable_filter,
-        shuffle_flags,
-        coverage=coverage
-    )
+    if not os.path.basename(build_dir).startswith('host_debug'):
+      # Test is disabled for flaking in debug runs:
+      # https://github.com/flutter/flutter/issues/127441
+      run_engine_executable(
+          build_dir,
+          'flutter_desktop_darwin_unittests',
+          executable_filter,
+          shuffle_flags,
+          coverage=coverage
+      )
     extra_env = {
         # pylint: disable=line-too-long
         # See https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early?language=objc