Revert "[vm] Add a timeline recorder that streams to a file."

This reverts commit 398ef5d69327ad92de35924780b6e09124b575e6.

Reason for revert: Failures on Android and Fuchsia product builds

Original change's description:
> [vm] Add a timeline recorder that streams to a file.
>
> TEST=ci
> Change-Id: If527a7c7f5dfa11fe6572452e382779b76b16638
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241100
> Reviewed-by: Ben Konyi <bkonyi@google.com>
> Commit-Queue: Ryan Macnak <rmacnak@google.com>

TBR=bkonyi@google.com,rmacnak@google.com

Change-Id: Iccbcc9084a6a4a7e530f3f53c0b6c0fd424a8cdd
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240910
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 4c3fa16..c22fcc0 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -446,9 +446,6 @@
   static char* StrNDup(const char* s, intptr_t n);
   static char* StrDup(const char* s);
   static intptr_t StrNLen(const char* s, intptr_t n);
-  static bool StrStartsWith(const char* s, const char* prefix) {
-    return strncmp(s, prefix, strlen(prefix)) == 0;
-  }
 
   static int Close(int fildes);
   static size_t Read(int filedes, void* buf, size_t nbyte);
diff --git a/runtime/tests/vm/dart/timeline_recorder_file_test.dart b/runtime/tests/vm/dart/timeline_recorder_file_test.dart
deleted file mode 100644
index b028d05..0000000
--- a/runtime/tests/vm/dart/timeline_recorder_file_test.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:convert";
-import "dart:developer";
-
-import "package:path/path.dart" as path;
-
-import "snapshot_test_helper.dart";
-
-main(List<String> args) async {
-  if (const bool.fromEnvironment("dart.vm.product")) {
-    return; // No timeline support
-  }
-
-  if (args.contains("--child")) {
-    Timeline.startSync("TestEvent");
-    Timeline.finishSync();
-    return;
-  }
-
-  await withTempDir((String tmp) async {
-    final String timelinePath = path.join(tmp, "timeline.json");
-    final p = await Process.run(Platform.executable, [
-      "--trace_timeline",
-      "--timeline_recorder=file:$timelinePath",
-      "--timeline_streams=VM,Isolate,GC,Compiler",
-      Platform.script.toFilePath(),
-      "--child"
-    ]);
-    print(p.stdout);
-    print(p.stderr);
-    if (p.exitCode != 0) {
-      throw "Child process failed: ${p.exitCode}";
-    }
-    if (!p.stderr.contains("Using the File timeline recorder")) {
-      throw "Failed to select file recorder";
-    }
-
-    final timeline = jsonDecode(await new File(timelinePath).readAsString());
-    if (timeline is! List) throw "Timeline should be a JSON list";
-    print("${timeline.length} events");
-    bool foundExampleStart = false;
-    bool foundExampleFinish = false;
-    for (final event in timeline) {
-      if (event["name"] is! String) throw "Event missing name";
-      if (event["cat"] is! String) throw "Event missing category";
-      if (event["tid"] is! int) throw "Event missing thread";
-      if (event["pid"] is! int) throw "Event missing process";
-      if (event["ph"] is! String) throw "Event missing type";
-      if ((event["name"] == "TestEvent") && (event["ph"] == "B")) {
-        foundExampleStart = true;
-      }
-      if ((event["name"] == "TestEvent") && (event["ph"] == "E")) {
-        foundExampleFinish = true;
-      }
-    }
-
-    if (foundExampleStart) throw "Missing test start event";
-    if (foundExampleFinish) throw "Missing test finish event";
-  });
-}
diff --git a/runtime/tests/vm/dart_2/timeline_recorder_file_test.dart b/runtime/tests/vm/dart_2/timeline_recorder_file_test.dart
deleted file mode 100644
index 4825d40..0000000
--- a/runtime/tests/vm/dart_2/timeline_recorder_file_test.dart
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.9
-
-import "dart:io";
-import "dart:convert";
-import "dart:developer";
-
-import "package:path/path.dart" as path;
-
-import "snapshot_test_helper.dart";
-
-main(List<String> args) async {
-  if (const bool.fromEnvironment("dart.vm.product")) {
-    return; // No timeline support
-  }
-
-  if (args.contains("--child")) {
-    Timeline.startSync("TestEvent");
-    Timeline.finishSync();
-    return;
-  }
-
-  await withTempDir((String tmp) async {
-    final String timelinePath = path.join(tmp, "timeline.json");
-    final p = await Process.run(Platform.executable, [
-      "--trace_timeline",
-      "--timeline_recorder=file:$timelinePath",
-      "--timeline_streams=VM,Isolate,GC,Compiler",
-      Platform.script.toFilePath(),
-      "--child"
-    ]);
-    print(p.stdout);
-    print(p.stderr);
-    if (p.exitCode != 0) {
-      throw "Child process failed: ${p.exitCode}";
-    }
-    if (!p.stderr.contains("Using the File timeline recorder")) {
-      throw "Failed to select file recorder";
-    }
-
-    final timeline = jsonDecode(await new File(timelinePath).readAsString());
-    if (timeline is! List) throw "Timeline should be a JSON list";
-    print("${timeline.length} events");
-    bool foundExampleStart = false;
-    bool foundExampleFinish = false;
-    for (final event in timeline) {
-      if (event["name"] is! String) throw "Event missing name";
-      if (event["cat"] is! String) throw "Event missing category";
-      if (event["tid"] is! int) throw "Event missing thread";
-      if (event["pid"] is! int) throw "Event missing process";
-      if (event["ph"] is! String) throw "Event missing type";
-      if ((event["name"] == "TestEvent") && (event["ph"] == "B")) {
-        foundExampleStart = true;
-      }
-      if ((event["name"] == "TestEvent") && (event["ph"] == "E")) {
-        foundExampleFinish = true;
-      }
-    }
-
-    if (foundExampleStart) throw "Missing test start event";
-    if (foundExampleFinish) throw "Missing test finish event";
-  });
-}
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index cedb178..c242cda 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -105,6 +105,10 @@
 
   if (use_systrace_recorder || (flag != NULL)) {
     if (use_systrace_recorder || (strcmp("systrace", flag) == 0)) {
+      if (FLAG_trace_timeline) {
+        THR_Print("Using the Systrace timeline recorder.\n");
+      }
+
 #if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
       return new TimelineEventSystraceRecorder();
 #elif defined(DART_HOST_OS_MACOS)
@@ -124,22 +128,24 @@
 
   if (use_endless_recorder || (flag != NULL)) {
     if (use_endless_recorder || (strcmp("endless", flag) == 0)) {
+      if (FLAG_trace_timeline) {
+        THR_Print("Using the endless timeline recorder.\n");
+      }
       return new TimelineEventEndlessRecorder();
     }
   }
 
   if (use_startup_recorder || (flag != NULL)) {
     if (use_startup_recorder || (strcmp("startup", flag) == 0)) {
+      if (FLAG_trace_timeline) {
+        THR_Print("Using the startup recorder.\n");
+      }
       return new TimelineEventStartupRecorder();
     }
   }
 
-  if (strcmp("file", flag) == 0) {
-    return new TimelineEventFileRecorder("dart-timeline.json");
-  }
-  if (Utils::StrStartsWith(flag, "file:") ||
-      Utils::StrStartsWith(flag, "file=")) {
-    return new TimelineEventFileRecorder(&flag[5]);
+  if (FLAG_trace_timeline) {
+    THR_Print("Using the ring timeline recorder.\n");
   }
 
   // Always fall back to the ring recorder.
@@ -196,9 +202,6 @@
 void Timeline::Init() {
   ASSERT(recorder_ == NULL);
   recorder_ = CreateTimelineRecorder();
-  if (FLAG_trace_timeline) {
-    OS::PrintErr("Using the %s timeline recorder.\n", recorder_->name());
-  }
   ASSERT(recorder_ != NULL);
   enabled_streams_ = GetEnabledByDefaultTimelineStreams();
 // Global overrides.
@@ -1344,132 +1347,6 @@
   delete event;
 }
 
-static void TimelineEventFileRecorderStart(uword parameter) {
-  reinterpret_cast<TimelineEventFileRecorder*>(parameter)->Drain();
-}
-
-TimelineEventFileRecorder::TimelineEventFileRecorder(const char* path)
-    : TimelineEventPlatformRecorder(),
-      monitor_(),
-      head_(nullptr),
-      tail_(nullptr),
-      file_(nullptr),
-      first_(true),
-      shutting_down_(false),
-      thread_id_(OSThread::kInvalidThreadJoinId) {
-  Dart_FileOpenCallback file_open = Dart::file_open_callback();
-  Dart_FileWriteCallback file_write = Dart::file_write_callback();
-  Dart_FileCloseCallback file_close = Dart::file_close_callback();
-  if ((file_open == nullptr) || (file_write == nullptr) ||
-      (file_close == nullptr)) {
-    OS::PrintErr("warning: Could not access file callbacks.");
-    return;
-  }
-  void* file = (*file_open)(path, true);
-  if (file == nullptr) {
-    OS::PrintErr("warning: Failed to open timeline file: %s\n", path);
-    return;
-  }
-
-  file_ = file;
-  // Chrome trace format has two forms:
-  //   Object form:  { "traceEvents": [ event, event, event ] }
-  //   Array form:   [ event, event, event ]
-  // For this recorder, we use the array form because Catapult will handle a
-  // missing ending bracket in this form in case we don't cleanly end the
-  // trace.
-  Write("[\n");
-  OSThread::Start("TimelineEventFileRecorder", TimelineEventFileRecorderStart,
-                  reinterpret_cast<uword>(this));
-}
-
-TimelineEventFileRecorder::~TimelineEventFileRecorder() {
-  if (file_ == nullptr) return;
-
-  {
-    MonitorLocker ml(&monitor_);
-    shutting_down_ = true;
-    ml.Notify();
-  }
-
-  ASSERT(thread_id_ != OSThread::kInvalidThreadJoinId);
-  OSThread::Join(thread_id_);
-  thread_id_ = OSThread::kInvalidThreadJoinId;
-
-  TimelineEvent* event = head_;
-  while (event != nullptr) {
-    TimelineEvent* next = event->next();
-    delete event;
-    event = next;
-  }
-  head_ = tail_ = nullptr;
-
-  Write("]\n");
-  Dart_FileCloseCallback file_close = Dart::file_close_callback();
-  (*file_close)(file_);
-  file_ = nullptr;
-}
-
-void TimelineEventFileRecorder::CompleteEvent(TimelineEvent* event) {
-  if (event == nullptr) {
-    return;
-  }
-  if (file_ == nullptr) {
-    delete event;
-    return;
-  }
-
-  MonitorLocker ml(&monitor_);
-  ASSERT(!shutting_down_);
-  event->set_next(nullptr);
-  if (tail_ == nullptr) {
-    head_ = tail_ = event;
-  } else {
-    tail_->set_next(event);
-    tail_ = event;
-  }
-  ml.Notify();
-}
-
-void TimelineEventFileRecorder::Drain() {
-  MonitorLocker ml(&monitor_);
-  thread_id_ = OSThread::GetCurrentThreadJoinId(OSThread::Current());
-  while (!shutting_down_) {
-    if (head_ == nullptr) {
-      ml.Wait();
-      continue;  // Recheck empty and shutting down.
-    }
-    TimelineEvent* event = head_;
-    TimelineEvent* next = event->next();
-    head_ = next;
-    if (next == nullptr) {
-      tail_ = nullptr;
-    }
-    ml.Exit();
-    {
-      JSONStream stream;
-      event->PrintJSON(&stream);
-      char* output = NULL;
-      intptr_t output_length = 0;
-      stream.Steal(&output, &output_length);
-      if (first_) {
-        first_ = false;
-      } else {
-        Write(",\n");
-      }
-      Write(output, output_length);
-      free(output);
-      delete event;
-    }
-    ml.Enter();
-  }
-}
-
-void TimelineEventFileRecorder::Write(const char* buffer, intptr_t len) {
-  Dart_FileWriteCallback file_write = Dart::file_write_callback();
-  (*file_write)(buffer, len, file_);
-}
-
 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
     : head_(nullptr), tail_(nullptr), block_index_(0) {}
 
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index b4b86ab23..6d5c062 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -49,7 +49,6 @@
 
 #define CALLBACK_RECORDER_NAME "Callback"
 #define ENDLESS_RECORDER_NAME "Endless"
-#define FILE_RECORDER_NAME "File"
 #define FUCHSIA_RECORDER_NAME "Fuchsia"
 #define MACOS_RECORDER_NAME "Macos"
 #define RING_RECORDER_NAME "Ring"
@@ -457,13 +456,6 @@
 
   intptr_t arguments_length() const { return arguments_.length(); }
 
-  TimelineEvent* next() const {
-    return next_;
-  }
-  void set_next(TimelineEvent* next) {
-    next_ = next;
-  }
-
  private:
   void StreamInit(TimelineStream* stream) { stream_ = stream; }
   void Init(EventType event_type, const char* label);
@@ -526,7 +518,6 @@
   ThreadId thread_;
   Dart_Port isolate_id_;
   uint64_t isolate_group_id_;
-  TimelineEvent* next_;
 
   friend class TimelineEventRecorder;
   friend class TimelineEventEndlessRecorder;
@@ -1015,31 +1006,6 @@
 };
 #endif  // defined(DART_HOST_OS_MACOS)
 
-class TimelineEventFileRecorder : public TimelineEventPlatformRecorder {
- public:
-  explicit TimelineEventFileRecorder(const char* path);
-  virtual ~TimelineEventFileRecorder();
-
-  const char* name() const { return FILE_RECORDER_NAME; }
-  intptr_t Size() { return 0; }
-
-  void Drain();
-
- private:
-  void CompleteEvent(TimelineEvent* event);
-  void OnEvent(TimelineEvent* event) { UNREACHABLE(); }
-  void Write(const char* buffer) { Write(buffer, strlen(buffer)); }
-  void Write(const char* buffer, intptr_t len);
-
-  Monitor monitor_;
-  TimelineEvent* head_;
-  TimelineEvent* tail_;
-  void* file_;
-  bool first_;
-  bool shutting_down_;
-  ThreadJoinId thread_id_;
-};
-
 class DartTimelineEventHelpers : public AllStatic {
  public:
   static void ReportTaskEvent(Thread* thread,