Merge "tp: fix generating table headers in G3"
diff --git a/Android.bp b/Android.bp
index 603f6ca..8a41156 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8222,6 +8222,7 @@
 filegroup {
     name: "perfetto_src_base_threading_threading",
     srcs: [
+        "src/base/threading/spawn.cc",
         "src/base/threading/stream_combinators.cc",
         "src/base/threading/thread_pool.cc",
     ],
@@ -8233,6 +8234,7 @@
     srcs: [
         "src/base/threading/channel_unittest.cc",
         "src/base/threading/future_unittest.cc",
+        "src/base/threading/spawn_unittest.cc",
         "src/base/threading/stream_unittest.cc",
         "src/base/threading/thread_pool_unittest.cc",
         "src/base/threading/util_unittest.cc",
@@ -9295,6 +9297,7 @@
         "src/trace_processor/importers/common/event_tracker.cc",
         "src/trace_processor/importers/common/flow_tracker.cc",
         "src/trace_processor/importers/common/global_args_tracker.cc",
+        "src/trace_processor/importers/common/metadata_tracker.cc",
         "src/trace_processor/importers/common/process_tracker.cc",
         "src/trace_processor/importers/common/slice_tracker.cc",
         "src/trace_processor/importers/common/slice_translation_table.cc",
@@ -9585,7 +9588,6 @@
         "src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc",
         "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
         "src/trace_processor/importers/proto/metadata_minimal_module.cc",
-        "src/trace_processor/importers/proto/metadata_tracker.cc",
         "src/trace_processor/importers/proto/network_trace_module.cc",
         "src/trace_processor/importers/proto/packet_analyzer.cc",
         "src/trace_processor/importers/proto/packet_sequence_state_generation.cc",
diff --git a/BUILD b/BUILD
index 080ae05..a79e0f2 100644
--- a/BUILD
+++ b/BUILD
@@ -1121,6 +1121,8 @@
         "src/trace_processor/importers/common/flow_tracker.h",
         "src/trace_processor/importers/common/global_args_tracker.cc",
         "src/trace_processor/importers/common/global_args_tracker.h",
+        "src/trace_processor/importers/common/metadata_tracker.cc",
+        "src/trace_processor/importers/common/metadata_tracker.h",
         "src/trace_processor/importers/common/process_tracker.cc",
         "src/trace_processor/importers/common/process_tracker.h",
         "src/trace_processor/importers/common/slice_tracker.cc",
@@ -1412,8 +1414,6 @@
         "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h",
         "src/trace_processor/importers/proto/metadata_minimal_module.cc",
         "src/trace_processor/importers/proto/metadata_minimal_module.h",
-        "src/trace_processor/importers/proto/metadata_tracker.cc",
-        "src/trace_processor/importers/proto/metadata_tracker.h",
         "src/trace_processor/importers/proto/network_trace_module.cc",
         "src/trace_processor/importers/proto/network_trace_module.h",
         "src/trace_processor/importers/proto/packet_analyzer.cc",
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index 0750e3c..2ac2948 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -1210,6 +1210,10 @@
   public_configs = [ ":zlib_config" ]
   deps = [ "//gn:default_deps" ]
 
+  if (is_win) {
+    defines = [ "X86_WINDOWS" ]
+  }
+
   # TODO(primiano): look into ADLER32_SIMD_SSSE3 and other SIMD optimizations
   # (from chromium's third_party/zlib/BUILD.gn).
 }
diff --git a/include/perfetto/ext/base/threading/BUILD.gn b/include/perfetto/ext/base/threading/BUILD.gn
index 9e557ec..d3a7b85 100644
--- a/include/perfetto/ext/base/threading/BUILD.gn
+++ b/include/perfetto/ext/base/threading/BUILD.gn
@@ -20,6 +20,7 @@
     "future.h",
     "future_combinators.h",
     "poll.h",
+    "spawn.h",
     "stream.h",
     "stream_combinators.h",
     "thread_pool.h",
diff --git a/include/perfetto/ext/base/threading/spawn.h b/include/perfetto/ext/base/threading/spawn.h
new file mode 100644
index 0000000..bf73fb9
--- /dev/null
+++ b/include/perfetto/ext/base/threading/spawn.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_BASE_THREADING_SPAWN_H_
+#define INCLUDE_PERFETTO_EXT_BASE_THREADING_SPAWN_H_
+
+#include <atomic>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/compiler.h"
+#include "perfetto/base/flat_set.h"
+#include "perfetto/base/platform_handle.h"
+#include "perfetto/base/task_runner.h"
+#include "perfetto/ext/base/event_fd.h"
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/thread_checker.h"
+#include "perfetto/ext/base/threading/channel.h"
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/poll.h"
+#include "perfetto/ext/base/threading/stream.h"
+#include "perfetto/ext/base/threading/stream_combinators.h"
+#include "perfetto/ext/base/threading/util.h"
+#include "perfetto/ext/base/uuid.h"
+#include "perfetto/ext/base/weak_ptr.h"
+
+namespace perfetto {
+namespace base {
+
+class PolledFuture;
+
+// A RAII object which tracks the polling of a Future.
+//
+// When this object is dropped, the backing Future will be cancelled as
+// soon as possible. In practice, the cancellation happens on the TaskRunner
+// thread so there can be some delay.
+class SpawnHandle {
+ public:
+  SpawnHandle(TaskRunner* task_runner, std::function<Future<FVoid>()> fn);
+  ~SpawnHandle();
+
+ private:
+  SpawnHandle(const SpawnHandle&) = delete;
+  SpawnHandle& operator=(const SpawnHandle&) = delete;
+
+  TaskRunner* task_runner_ = nullptr;
+  std::shared_ptr<std::unique_ptr<PolledFuture>> polled_future_;
+};
+
+// Specialization of SpawnHandle used by Futures/Streams which return T.
+//
+// Values of T are returned through a Channel<T> which allows reading these
+// values on a different thread to where the polling happens.
+template <typename T>
+class ResultSpawnHandle {
+ public:
+  ResultSpawnHandle(TaskRunner* task_runner,
+                    std::shared_ptr<Channel<T>> channel,
+                    std::function<Future<FVoid>()> fn)
+      : handle_(task_runner, std::move(fn)), channel_(std::move(channel)) {}
+
+  Channel<T>* channel() const { return channel_.get(); }
+
+ private:
+  SpawnHandle handle_;
+  std::shared_ptr<Channel<T>> channel_;
+};
+
+// "Spawns" a Future<FVoid> on the given TaskRunner and returns an RAII
+// SpawnHandle which can be used to cancel the spawn.
+//
+// Spawning a Future means to poll it to completion. In Perfetto, this is done
+// by using a TaskRunner object to track FD readiness and polling the Future
+// when progress can be made.
+//
+// The returned SpawnHandle should be stashed as it is responsible for the
+// lifetime of the pollling. If the SpawnHandle is dropped, the Future is
+// cancelled and dropped ASAP (this happens on the TaskRunner thread so there
+// can be some delay).
+PERFETTO_WARN_UNUSED_RESULT inline SpawnHandle SpawnFuture(
+    TaskRunner* task_runner,
+    std::function<Future<FVoid>()> fn) {
+  return SpawnHandle(task_runner, std::move(fn));
+}
+
+// Variant of |SpawnFuture| for a Stream<T> allowing returning items of T.
+//
+// See ResultSpawnHandle for how elements from the stream can be consumed.
+template <typename T>
+PERFETTO_WARN_UNUSED_RESULT inline ResultSpawnHandle<T> SpawnResultStream(
+    TaskRunner* task_runner,
+    std::function<Stream<T>()> fn) {
+  class AllVoidCollector : public Collector<FVoid, FVoid> {
+   public:
+    Optional<FVoid> OnNext(FVoid) override { return nullopt; }
+    FVoid OnDone() override { return FVoid(); }
+  };
+  auto channel = std::make_shared<Channel<T>>(4);
+  return ResultSpawnHandle<T>(
+      task_runner, channel, [c = channel, fn = std::move(fn)]() {
+        return fn()
+            .MapFuture([c](T value) {
+              return WriteChannelFuture(c.get(), std::move(value));
+            })
+            .Concat(OnDestroyStream<FVoid>([c]() { c->Close(); }))
+            .Collect(std::unique_ptr<Collector<FVoid, FVoid>>(
+                new AllVoidCollector()));
+      });
+}
+
+// Variant of |SpawnFuture| for a Future<T> allowing returning items of T.
+//
+// See ResultSpawnHandle for how elements from the future can be consumed.
+template <typename T>
+PERFETTO_WARN_UNUSED_RESULT inline ResultSpawnHandle<T> SpawnResultFuture(
+    TaskRunner* task_runner,
+    std::function<Future<T>()> fn) {
+  return SpawnResultStream<T>(task_runner, [fn = std::move(fn)]() {
+    return StreamFromFuture(std::move(fn()));
+  });
+}
+
+}  // namespace base
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_EXT_BASE_THREADING_SPAWN_H_
diff --git a/src/android_stats/perfetto_atoms.h b/src/android_stats/perfetto_atoms.h
index 5a5eef0..e9ef08e 100644
--- a/src/android_stats/perfetto_atoms.h
+++ b/src/android_stats/perfetto_atoms.h
@@ -70,6 +70,7 @@
   kTracedStartTracingInvalidSessionState = 36,
   kTracedEnableTracingInvalidFilter = 47,
   kTracedEnableTracingOobTargetBuffer = 48,
+  kTracedEnableTracingInvalidTriggerMode = 52,
 
   // Checkpoints inside perfetto_cmd after tracing has finished.
   kOnTracingDisabled = 4,
diff --git a/src/base/threading/BUILD.gn b/src/base/threading/BUILD.gn
index 3a31723..23343bc 100644
--- a/src/base/threading/BUILD.gn
+++ b/src/base/threading/BUILD.gn
@@ -15,9 +15,13 @@
 import("../../../gn/test.gni")
 
 source_set("threading") {
-  deps = [ "../../../gn:default_deps" ]
+  deps = [
+    "..:base",
+    "../../../gn:default_deps",
+  ]
   public_deps = [ "../../../include/perfetto/ext/base/threading" ]
   sources = [
+    "spawn.cc",
     "stream_combinators.cc",
     "thread_pool.cc",
   ]
@@ -28,12 +32,14 @@
   deps = [
     ":threading",
     "..:base",
+    "..:test_support",
     "../../../gn:default_deps",
     "../../../gn:gtest_and_gmock",
   ]
   sources = [
     "channel_unittest.cc",
     "future_unittest.cc",
+    "spawn_unittest.cc",
     "stream_unittest.cc",
     "thread_pool_unittest.cc",
     "util_unittest.cc",
diff --git a/src/base/threading/spawn.cc b/src/base/threading/spawn.cc
new file mode 100644
index 0000000..4fd246a
--- /dev/null
+++ b/src/base/threading/spawn.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/ext/base/threading/spawn.h"
+
+#include "perfetto/base/task_runner.h"
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/thread_checker.h"
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/poll.h"
+#include "perfetto/ext/base/threading/stream.h"
+
+namespace perfetto {
+namespace base {
+
+// Represents a future which is being polled to completion. Owned by
+// SpawnHandle.
+class PolledFuture {
+ public:
+  explicit PolledFuture(TaskRunner* task_runner, Future<FVoid> future)
+      : task_runner_(task_runner), future_(std::move(future)) {
+    PERFETTO_DCHECK(task_runner_->RunsTasksOnCurrentThread());
+    PollUntilFinish();
+  }
+
+  ~PolledFuture() {
+    PERFETTO_DCHECK_THREAD(thread_checker);
+    ClearFutureAndWatches(interested_);
+  }
+
+ private:
+  PolledFuture(PolledFuture&&) = delete;
+  PolledFuture& operator=(PolledFuture&&) = delete;
+
+  void PollUntilFinish() {
+    PERFETTO_DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+    auto pre_poll_interested = std::move(interested_);
+    interested_.clear();
+
+    FuturePollResult<FVoid> res = future_->Poll(&context_);
+    if (!res.IsPending()) {
+      ClearFutureAndWatches(pre_poll_interested);
+      return;
+    }
+
+    for (PlatformHandle fd : SetDifference(pre_poll_interested, interested_)) {
+      task_runner_->RemoveFileDescriptorWatch(fd);
+    }
+
+    auto weak_this = weak_ptr_factory_.GetWeakPtr();
+    for (PlatformHandle fd : SetDifference(interested_, pre_poll_interested)) {
+      task_runner_->AddFileDescriptorWatch(fd, [weak_this, fd]() {
+        if (!weak_this) {
+          return;
+        }
+        weak_this->ready_ = {fd};
+        weak_this->PollUntilFinish();
+      });
+    }
+  }
+
+  void ClearFutureAndWatches(FlatSet<PlatformHandle> interested) {
+    future_ = nullopt;
+    for (PlatformHandle fd : interested) {
+      task_runner_->RemoveFileDescriptorWatch(fd);
+    }
+    interested_.clear();
+    ready_.clear();
+  }
+
+  static std::vector<PlatformHandle> SetDifference(
+      const FlatSet<PlatformHandle>& f,
+      const FlatSet<PlatformHandle>& s) {
+    std::vector<PlatformHandle> out(f.size());
+    auto it = std::set_difference(f.begin(), f.end(), s.begin(), s.end(),
+                                  out.begin());
+    out.resize(static_cast<size_t>(std::distance(out.begin(), it)));
+    return out;
+  }
+
+  TaskRunner* const task_runner_ = nullptr;
+
+  Optional<Future<FVoid>> future_;
+  FlatSet<PlatformHandle> interested_;
+  FlatSet<PlatformHandle> ready_;
+  PollContext context_{&interested_, &ready_};
+
+  PERFETTO_THREAD_CHECKER(thread_checker)
+
+  // Keep this last.
+  WeakPtrFactory<PolledFuture> weak_ptr_factory_{this};
+};
+
+SpawnHandle::SpawnHandle(TaskRunner* task_runner,
+                         std::function<Future<FVoid>()> fn)
+    : task_runner_(task_runner),
+      polled_future_(std::make_shared<std::unique_ptr<PolledFuture>>()) {
+  task_runner->PostTask(
+      [t = task_runner, fn = std::move(fn), p = polled_future_]() mutable {
+        p->reset(new PolledFuture(t, fn()));
+      });
+}
+
+SpawnHandle::~SpawnHandle() {
+  task_runner_->PostTask(
+      [f = std::move(polled_future_)]() mutable { f.reset(); });
+}
+
+}  // namespace base
+}  // namespace perfetto
diff --git a/src/base/threading/spawn_unittest.cc b/src/base/threading/spawn_unittest.cc
new file mode 100644
index 0000000..1324b18
--- /dev/null
+++ b/src/base/threading/spawn_unittest.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/ext/base/threading/spawn.h"
+
+#include "perfetto/ext/base/event_fd.h"
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/thread_task_runner.h"
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/poll.h"
+#include "perfetto/ext/base/threading/util.h"
+#include "perfetto/ext/base/unix_task_runner.h"
+#include "src/base/test/test_task_runner.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace base {
+namespace {
+
+using ::testing::_;
+using ::testing::Return;
+
+template <typename T>
+class MockFuturePollable : public FuturePollable<T> {
+ public:
+  MOCK_METHOD1(Poll, FuturePollResult<T>(PollContext*));
+};
+
+template <typename T>
+class MockStreamPollable : public StreamPollable<T> {
+ public:
+  MOCK_METHOD1(PollNext, StreamPollResult<T>(PollContext*));
+};
+
+TEST(SpawnUnittest, SpawnFuture) {
+  base::TestTaskRunner task_runner;
+
+  base::EventFd fd;
+  auto pollable = std::make_unique<MockFuturePollable<int>>();
+  EXPECT_CALL(*pollable, Poll(_))
+      .WillOnce([&fd](PollContext* ctx) {
+        fd.Clear();
+        ctx->RegisterInterested(fd.fd());
+        return PendingPollResult();
+      })
+      .WillOnce(Return(FuturePollResult<int>(1024)));
+  auto res = SpawnResultFuture<int>(
+      &task_runner,
+      [pollable = std::make_shared<std::unique_ptr<MockFuturePollable<int>>>(
+           std::move(pollable))]() mutable {
+        return base::Future<int>(std::move(*pollable));
+      });
+
+  task_runner.RunUntilIdle();
+  ASSERT_EQ(res.channel()->ReadNonBlocking().item, base::nullopt);
+
+  task_runner.RunUntilIdle();
+  ASSERT_EQ(res.channel()->ReadNonBlocking().item, base::nullopt);
+
+  fd.Notify();
+  task_runner.RunUntilIdle();
+
+  auto read = res.channel()->ReadNonBlocking();
+  ASSERT_EQ(read.item, 1024);
+  ASSERT_TRUE(read.is_closed);
+
+  read = res.channel()->ReadNonBlocking();
+  ASSERT_TRUE(read.is_closed);
+}
+
+TEST(SpawnUnittest, SpawnStream) {
+  base::TestTaskRunner task_runner;
+
+  base::EventFd fd;
+  auto pollable = std::make_unique<MockStreamPollable<int>>();
+  EXPECT_CALL(*pollable, PollNext(_))
+      .WillOnce([&fd](PollContext* ctx) {
+        fd.Clear();
+        ctx->RegisterInterested(fd.fd());
+        return PendingPollResult();
+      })
+      .WillOnce(Return(StreamPollResult<int>(1024)))
+      .WillOnce([&fd](PollContext* ctx) {
+        fd.Clear();
+        ctx->RegisterInterested(fd.fd());
+        return PendingPollResult();
+      })
+      .WillOnce(Return(StreamPollResult<int>(2048)))
+      .WillOnce(Return(DonePollResult()));
+  auto res = SpawnResultStream<int>(
+      &task_runner,
+      [pollable = std::make_shared<std::unique_ptr<MockStreamPollable<int>>>(
+           std::move(pollable))]() mutable {
+        return base::Stream<int>(std::move(*pollable));
+      });
+
+  task_runner.RunUntilIdle();
+  ASSERT_EQ(res.channel()->ReadNonBlocking().item, base::nullopt);
+
+  fd.Notify();
+  task_runner.RunUntilIdle();
+
+  auto read = res.channel()->ReadNonBlocking();
+  ASSERT_EQ(read.item, 1024);
+  ASSERT_FALSE(read.is_closed);
+
+  task_runner.RunUntilIdle();
+  ASSERT_EQ(res.channel()->ReadNonBlocking().item, base::nullopt);
+
+  fd.Notify();
+  task_runner.RunUntilIdle();
+
+  read = res.channel()->ReadNonBlocking();
+  ASSERT_EQ(read.item, 2048);
+  ASSERT_TRUE(read.is_closed);
+}
+
+}  // namespace
+}  // namespace base
+}  // namespace perfetto
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index 07722a0..823bc17 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -28,9 +28,9 @@
 #include "perfetto/ext/base/temp_file.h"
 #include "src/trace_processor/importers/common/args_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/track_event_tracker.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/types/trace_processor_context.h"
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index 22a1154..7795398 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -33,6 +33,8 @@
     "flow_tracker.h",
     "global_args_tracker.cc",
     "global_args_tracker.h",
+    "metadata_tracker.cc",
+    "metadata_tracker.h",
     "process_tracker.cc",
     "process_tracker.h",
     "slice_tracker.cc",
diff --git a/src/trace_processor/importers/common/clock_tracker.cc b/src/trace_processor/importers/common/clock_tracker.cc
index a2feea9..987739c 100644
--- a/src/trace_processor/importers/common/clock_tracker.cc
+++ b/src/trace_processor/importers/common/clock_tracker.cc
@@ -36,8 +36,8 @@
 
 using Clock = protos::pbzero::ClockSnapshot::Clock;
 
-ClockTracker::ClockTracker(TraceStorage* storage)
-    : storage_(storage),
+ClockTracker::ClockTracker(TraceProcessorContext* context)
+    : context_(context),
       trace_time_clock_id_(protos::pbzero::BUILTIN_CLOCK_BOOTTIME) {}
 
 ClockTracker::~ClockTracker() = default;
@@ -67,7 +67,7 @@
                       " cannot use incremental encoding; this is only "
                       "supported for sequence-scoped clocks.",
                       clock_id);
-        storage_->IncrementStats(stats::invalid_clock_snapshots);
+        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
         return snapshot_id;
       }
       domain.unit_multiplier_ns = clock_ts.clock.unit_multiplier_ns;
@@ -83,7 +83,7 @@
                     clock_id, clock_ts.clock.unit_multiplier_ns,
                     clock_ts.clock.is_incremental, domain.unit_multiplier_ns,
                     domain.is_incremental);
-      storage_->IncrementStats(stats::invalid_clock_snapshots);
+      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
       return snapshot_id;
     }
     const int64_t timestamp_ns = clock_ts.timestamp * domain.unit_multiplier_ns;
@@ -95,7 +95,7 @@
       PERFETTO_ELOG("Clock sync error: duplicate clock domain with id=%" PRIu64
                     " at snapshot %" PRIu32 ".",
                     clock_id, snapshot_id);
-      storage_->IncrementStats(stats::invalid_clock_snapshots);
+      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
       return snapshot_id;
     }
 
@@ -119,7 +119,7 @@
                       " not >= %" PRId64 ".",
                       clock_id, snapshot_id, timestamp_ns,
                       vect.timestamps_ns.back());
-        storage_->IncrementStats(stats::invalid_clock_snapshots);
+        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
         return snapshot_id;
       }
 
@@ -220,12 +220,12 @@
   PERFETTO_DCHECK(!IsSequenceClock(src_clock_id));
   PERFETTO_DCHECK(!IsSequenceClock(target_clock_id));
 
-  storage_->IncrementStats(stats::clock_sync_cache_miss);
+  context_->storage->IncrementStats(stats::clock_sync_cache_miss);
 
   ClockPath path = FindPath(src_clock_id, target_clock_id);
   if (!path.valid()) {
     // Too many logs maybe emitted when path is invalid.
-    storage_->IncrementStats(stats::clock_sync_failure);
+    context_->storage->IncrementStats(stats::clock_sync_failure);
     return base::ErrStatus("No path from clock %" PRIu64 " to %" PRIu64
                            " at timestamp %" PRId64,
                            src_clock_id, target_clock_id, src_timestamp);
diff --git a/src/trace_processor/importers/common/clock_tracker.h b/src/trace_processor/importers/common/clock_tracker.h
index 2e4a3b1..81588e6 100644
--- a/src/trace_processor/importers/common/clock_tracker.h
+++ b/src/trace_processor/importers/common/clock_tracker.h
@@ -30,7 +30,9 @@
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/status_or.h"
 #include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -116,9 +118,9 @@
 
 class ClockTracker {
  public:
-  using ClockId = uint64_t;
+  using ClockId = int64_t;
 
-  explicit ClockTracker(TraceStorage*);
+  explicit ClockTracker(TraceProcessorContext*);
   virtual ~ClockTracker();
 
   // Clock description.
@@ -153,7 +155,7 @@
   // passed as argument to ClockTracker functions.
   static ClockId SeqenceToGlobalClock(uint32_t seq_id, uint32_t clock_id) {
     PERFETTO_DCHECK(IsSequenceClock(clock_id));
-    return (static_cast<uint64_t>(seq_id) << 32) | clock_id;
+    return (static_cast<int64_t>(seq_id) << 32) | clock_id;
   }
 
   // Appends a new snapshot for the given clock domains.
@@ -162,6 +164,12 @@
   uint32_t AddSnapshot(const std::vector<ClockTimestamp>&);
 
   base::StatusOr<int64_t> ToTraceTime(ClockId clock_id, int64_t timestamp) {
+    if (PERFETTO_UNLIKELY(!trace_time_clock_id_used_for_conversion_)) {
+      context_->metadata_tracker->SetMetadata(
+          metadata::trace_time_clock_id,
+          Variadic::Integer(trace_time_clock_id_));
+      trace_time_clock_id_used_for_conversion_ = true;
+    }
     trace_time_clock_id_used_for_conversion_ = true;
     if (clock_id == trace_time_clock_id_)
       return timestamp;
@@ -189,6 +197,8 @@
       return;
     }
     trace_time_clock_id_ = clock_id;
+    context_->metadata_tracker->SetMetadata(
+        metadata::trace_time_clock_id, Variadic::Integer(trace_time_clock_id_));
   }
 
   void set_cache_lookups_disabled_for_testing(bool v) {
@@ -328,7 +338,7 @@
     return &it->second;
   }
 
-  TraceStorage* const storage_;
+  TraceProcessorContext* const context_;
   ClockId trace_time_clock_id_ = 0;
   std::map<ClockId, ClockDomain> clocks_;
   std::set<ClockGraphEdge> graph_;
diff --git a/src/trace_processor/importers/common/clock_tracker_unittest.cc b/src/trace_processor/importers/common/clock_tracker_unittest.cc
index 0614372..e625111 100644
--- a/src/trace_processor/importers/common/clock_tracker_unittest.cc
+++ b/src/trace_processor/importers/common/clock_tracker_unittest.cc
@@ -19,6 +19,7 @@
 #include <random>
 
 #include "perfetto/ext/base/optional.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 #include "test/gtest_and_gmock.h"
@@ -31,9 +32,15 @@
 
 class ClockTrackerTest : public ::testing::Test {
  public:
+  ClockTrackerTest() {
+    context_.storage.reset(new TraceStorage());
+    context_.metadata_tracker.reset(
+        new MetadataTracker(context_.storage.get()));
+  }
+
   // using ClockId = uint64_t;
-  TraceStorage storage_;
-  ClockTracker ct_{&storage_};
+  TraceProcessorContext context_;
+  ClockTracker ct_{&context_};
   base::StatusOr<int64_t> Convert(ClockTracker::ClockId src_clock_id,
                                   int64_t src_timestamp,
                                   ClockTracker::ClockId target_clock_id) {
diff --git a/src/trace_processor/importers/proto/metadata_tracker.cc b/src/trace_processor/importers/common/metadata_tracker.cc
similarity index 98%
rename from src/trace_processor/importers/proto/metadata_tracker.cc
rename to src/trace_processor/importers/common/metadata_tracker.cc
index a5e6928..010b1b7 100644
--- a/src/trace_processor/importers/proto/metadata_tracker.cc
+++ b/src/trace_processor/importers/common/metadata_tracker.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 
 #include "perfetto/ext/base/crash_keys.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
diff --git a/src/trace_processor/importers/proto/metadata_tracker.h b/src/trace_processor/importers/common/metadata_tracker.h
similarity index 91%
rename from src/trace_processor/importers/proto/metadata_tracker.h
rename to src/trace_processor/importers/common/metadata_tracker.h
index c3e587e..80cace9 100644
--- a/src/trace_processor/importers/proto/metadata_tracker.h
+++ b/src/trace_processor/importers/common/metadata_tracker.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_METADATA_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_METADATA_TRACKER_H_
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_METADATA_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_METADATA_TRACKER_H_
 
 #include "src/trace_processor/storage/trace_storage.h"
 
@@ -70,4 +70,4 @@
 }  // namespace trace_processor
 }  // namespace perfetto
 
-#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_METADATA_TRACKER_H_
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_METADATA_TRACKER_H_
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 7033130..78157d1 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -22,6 +22,7 @@
 #include "perfetto/protozero/proto_decoder.h"
 #include "src/trace_processor/importers/common/args_tracker.h"
 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/parser_types.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/ftrace/binder_tracker.h"
@@ -29,7 +30,6 @@
 #include "src/trace_processor/importers/ftrace/v4l2_tracker.h"
 #include "src/trace_processor/importers/ftrace/virtio_video_tracker.h"
 #include "src/trace_processor/importers/i2c/i2c_tracker.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
 #include "src/trace_processor/importers/systrace/systrace_parser.h"
@@ -1403,7 +1403,6 @@
       evt.func_name(), tgid, evt.value());
 }
 
-
 /** Parses ion heap events present in Pixel kernels. */
 void FtraceParser::ParseIonHeapGrowOrShrink(int64_t timestamp,
                                             uint32_t pid,
@@ -1717,7 +1716,8 @@
                                        ThreadNamePriority::kFtrace);
   proc_tracker->AssociateThreads(source_utid, new_utid);
 
-  ThreadStateTracker::GetOrCreate(context_)->PushNewTaskEvent(timestamp, new_utid, source_utid);
+  ThreadStateTracker::GetOrCreate(context_)->PushNewTaskEvent(
+      timestamp, new_utid, source_utid);
 }
 
 void FtraceParser::ParseTaskRename(ConstBytes blob) {
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
index 92ccb20..349e9d0 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
@@ -26,13 +26,13 @@
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/slice_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
 #include "src/trace_processor/importers/proto/additional_modules.h"
 #include "src/trace_processor/importers/proto/default_modules.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/proto_trace_parser.h"
 #include "src/trace_processor/importers/proto/stack_profile_tracker.h"
 #include "src/trace_processor/sorter/trace_sorter.h"
@@ -228,7 +228,7 @@
     slice_ = new NiceMock<MockSliceTracker>(&context_);
     context_.slice_tracker.reset(slice_);
     context_.slice_translation_table.reset(new SliceTranslationTable(storage_));
-    context_.clock_tracker.reset(new ClockTracker(context_.storage.get()));
+    context_.clock_tracker.reset(new ClockTracker(&context_));
     clock_ = context_.clock_tracker.get();
     context_.flow_tracker.reset(new FlowTracker(&context_));
     context_.sorter.reset(new TraceSorter(&context_, CreateParser(),
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index 07bdd19..47bf6c7 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -34,8 +34,6 @@
     "memory_tracker_snapshot_parser.h",
     "metadata_minimal_module.cc",
     "metadata_minimal_module.h",
-    "metadata_tracker.cc",
-    "metadata_tracker.h",
     "network_trace_module.cc",
     "network_trace_module.h",
     "packet_analyzer.cc",
diff --git a/src/trace_processor/importers/proto/android_probes_parser.cc b/src/trace_processor/importers/proto/android_probes_parser.cc
index 6d37b9c..7827d50 100644
--- a/src/trace_processor/importers/proto/android_probes_parser.cc
+++ b/src/trace_processor/importers/proto/android_probes_parser.cc
@@ -23,8 +23,8 @@
 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
 #include "src/trace_processor/types/tcp_state.h"
 #include "src/trace_processor/types/trace_processor_context.h"
diff --git a/src/trace_processor/importers/proto/metadata_minimal_module.cc b/src/trace_processor/importers/proto/metadata_minimal_module.cc
index d29b3d3..099cdac 100644
--- a/src/trace_processor/importers/proto/metadata_minimal_module.cc
+++ b/src/trace_processor/importers/proto/metadata_minimal_module.cc
@@ -17,7 +17,7 @@
 #include "src/trace_processor/importers/proto/metadata_minimal_module.h"
 
 #include "perfetto/ext/base/base64.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 
 #include "protos/perfetto/trace/chrome/chrome_benchmark_metadata.pbzero.h"
diff --git a/src/trace_processor/importers/proto/metadata_module.cc b/src/trace_processor/importers/proto/metadata_module.cc
index 81a4ce6..3374043 100644
--- a/src/trace_processor/importers/proto/metadata_module.cc
+++ b/src/trace_processor/importers/proto/metadata_module.cc
@@ -18,10 +18,10 @@
 
 #include "perfetto/ext/base/base64.h"
 #include "perfetto/ext/base/uuid.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/slice_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/proto/config.descriptor.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/util/descriptors.h"
 #include "src/trace_processor/util/protozero_to_text.h"
 
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index 600b886..fa1ffd6 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -30,12 +30,12 @@
 
 #include "src/trace_processor/importers/common/args_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/parser_types.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/slice_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/ftrace/ftrace_module.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
 #include "src/trace_processor/importers/proto/track_event_module.h"
 #include "src/trace_processor/storage/metadata.h"
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index 5b907a3..ff841aa 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -25,13 +25,13 @@
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/slice_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
 #include "src/trace_processor/importers/proto/additional_modules.h"
 #include "src/trace_processor/importers/proto/default_modules.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/proto_trace_parser.h"
 #include "src/trace_processor/importers/proto/stack_profile_tracker.h"
 #include "src/trace_processor/sorter/trace_sorter.h"
@@ -243,7 +243,7 @@
     slice_ = new NiceMock<MockSliceTracker>(&context_);
     context_.slice_tracker.reset(slice_);
     context_.slice_translation_table.reset(new SliceTranslationTable(storage_));
-    clock_ = new ClockTracker(context_.storage.get());
+    clock_ = new ClockTracker(&context_);
     context_.clock_tracker.reset(clock_);
     context_.flow_tracker.reset(new FlowTracker(&context_));
     context_.sorter.reset(new TraceSorter(&context_, CreateParser(),
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index cb0567b..f3b06fb 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -28,9 +28,9 @@
 #include "perfetto/trace_processor/status.h"
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/ftrace/ftrace_module.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/packet_analyzer.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
 #include "src/trace_processor/importers/proto/proto_incremental_state.h"
@@ -399,7 +399,7 @@
 }
 
 base::Optional<StringId> ProtoTraceReader::GetBuiltinClockNameOrNull(
-    uint64_t clock_id) {
+    int64_t clock_id) {
   switch (clock_id) {
     case protos::pbzero::ClockSnapshot::Clock::REALTIME:
       return context_->storage->InternString("REALTIME");
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index 471503a..3776358 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -75,7 +75,7 @@
                          TraceBlobView interned_data);
   void ParseTraceConfig(ConstBytes);
 
-  base::Optional<StringId> GetBuiltinClockNameOrNull(uint64_t clock_id);
+  base::Optional<StringId> GetBuiltinClockNameOrNull(int64_t clock_id);
 
   PacketSequenceState* GetIncrementalStateForPacketSequence(
       uint32_t sequence_id) {
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index a16ca4a..3a3c438 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -23,9 +23,9 @@
 #include "perfetto/ext/traced/sys_stats_counters.h"
 #include "perfetto/protozero/proto_decoder.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/system_info_tracker.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
 #include "src/trace_processor/storage/metadata.h"
 #include "src/trace_processor/types/trace_processor_context.h"
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index 314d205..35c76a3 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -19,9 +19,9 @@
 #include "perfetto/base/logging.h"
 #include "perfetto/trace_processor/trace_blob_view.h"
 #include "src/trace_processor/importers/common/clock_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
 #include "src/trace_processor/importers/proto/proto_trace_reader.h"
 #include "src/trace_processor/importers/proto/track_event_tracker.h"
diff --git a/src/trace_processor/storage/metadata.h b/src/trace_processor/storage/metadata.h
index de2e651..88eac06 100644
--- a/src/trace_processor/storage/metadata.h
+++ b/src/trace_processor/storage/metadata.h
@@ -50,6 +50,7 @@
   F(system_version,                    KeyType::kSingle,  Variadic::kString), \
   F(trace_config_pbtxt,                KeyType::kSingle,  Variadic::kString), \
   F(trace_size_bytes,                  KeyType::kSingle,  Variadic::kInt),    \
+  F(trace_time_clock_id,               KeyType::kSingle,  Variadic::kInt),    \
   F(trace_type,                        KeyType::kSingle,  Variadic::kString), \
   F(trace_uuid,                        KeyType::kSingle,  Variadic::kString), \
   F(tracing_disabled_ns,               KeyType::kSingle,  Variadic::kInt),    \
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index 29fa474..b407e19 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -26,13 +26,13 @@
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
 #include "src/trace_processor/importers/common/global_args_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/slice_tracker.h"
 #include "src/trace_processor/importers/common/slice_translation_table.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/ftrace/ftrace_module.h"
 #include "src/trace_processor/importers/proto/heap_profile_tracker.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/perf_sample_tracker.h"
 #include "src/trace_processor/importers/proto/proto_importer_module.h"
 #include "src/trace_processor/importers/proto/proto_trace_parser.h"
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 24bb87e..7c38b98 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -33,6 +33,7 @@
 #include "perfetto/trace_processor/basic_types.h"
 #include "src/trace_processor/importers/android_bugreport/android_bugreport_parser.h"
 #include "src/trace_processor/importers/common/clock_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
 #include "src/trace_processor/importers/fuchsia/fuchsia_trace_parser.h"
 #include "src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h"
@@ -43,7 +44,6 @@
 #include "src/trace_processor/importers/ninja/ninja_log_parser.h"
 #include "src/trace_processor/importers/proto/additional_modules.h"
 #include "src/trace_processor/importers/proto/content_analyzer.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/systrace/systrace_trace_parser.h"
 #include "src/trace_processor/iterator_impl.h"
 #include "src/trace_processor/prelude/functions/create_function.h"
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index 3bea7eb..75031f8 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -25,6 +25,7 @@
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/slice_tracker.h"
 #include "src/trace_processor/importers/common/slice_translation_table.h"
@@ -32,7 +33,6 @@
 #include "src/trace_processor/importers/proto/chrome_track_event.descriptor.h"
 #include "src/trace_processor/importers/proto/default_modules.h"
 #include "src/trace_processor/importers/proto/heap_profile_tracker.h"
-#include "src/trace_processor/importers/proto/metadata_tracker.h"
 #include "src/trace_processor/importers/proto/packet_analyzer.h"
 #include "src/trace_processor/importers/proto/perf_sample_tracker.h"
 #include "src/trace_processor/importers/proto/proto_importer_module.h"
@@ -60,7 +60,7 @@
   context_.flow_tracker.reset(new FlowTracker(&context_));
   context_.event_tracker.reset(new EventTracker(&context_));
   context_.process_tracker.reset(new ProcessTracker(&context_));
-  context_.clock_tracker.reset(new ClockTracker(context_.storage.get()));
+  context_.clock_tracker.reset(new ClockTracker(&context_));
   context_.heap_profile_tracker.reset(new HeapProfileTracker(&context_));
   context_.perf_sample_tracker.reset(new PerfSampleTracker(&context_));
   context_.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index a590837..5277657 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -623,6 +623,15 @@
         cfg.trigger_config().trigger_timeout_ms());
   }
 
+  // This check has been introduced in May 2023 after finding b/274931668.
+  if (static_cast<int>(cfg.trigger_config().trigger_mode()) >
+      TraceConfig::TriggerConfig::TriggerMode_MAX) {
+    MaybeLogUploadEvent(
+        cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidTriggerMode);
+    return PERFETTO_SVC_ERR(
+        "The trace config specified an invalid trigger_mode");
+  }
+
   if (has_trigger_config && cfg.duration_ms() != 0) {
     MaybeLogUploadEvent(
         cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingDurationWithTrigger);
@@ -982,6 +991,9 @@
       tracing_session->config.set_duration_ms(
           cfg.trigger_config().trigger_timeout_ms());
       break;
+
+      // The case of unknown modes (coming from future versions of the service)
+      // is handled few lines above (search for TriggerMode_MAX).
   }
 
   tracing_session->state = TracingSession::CONFIGURED;
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index 8b8c62c..b66e502 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -432,6 +432,31 @@
   EXPECT_THAT(consumer->ReadBuffers(), IsEmpty());
 }
 
+// Regression test for b/274931668. An unkonwn trigger should not cause a trace
+// that runs indefinitely.
+TEST_F(TracingServiceImplTest, FailOnUnknownTrigger) {
+  std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+  consumer->Connect(svc.get());
+
+  std::unique_ptr<MockProducer> producer = CreateMockProducer();
+  producer->Connect(svc.get(), "mock_producer");
+  producer->RegisterDataSource("ds_1");
+
+  TraceConfig trace_config;
+  trace_config.add_buffers()->set_size_kb(128);
+  trace_config.add_data_sources()->mutable_config()->set_name("ds_1");
+  auto* trigger_config = trace_config.mutable_trigger_config();
+  trigger_config->set_trigger_mode(
+      static_cast<TraceConfig::TriggerConfig::TriggerMode>(
+          TraceConfig::TriggerConfig::TriggerMode_MAX + 1));
+  auto* trigger = trigger_config->add_triggers();
+  trigger->set_name("trigger_from_the_future");
+  trigger_config->set_trigger_timeout_ms(1);
+
+  consumer->EnableTracing(trace_config);
+  consumer->WaitForTracingDisabled();
+}
+
 // Creates a tracing session with a START_TRACING trigger and checks that
 // the session is not started when the configured trigger producer is different
 // than the producer that sent the trigger.
diff --git a/test/trace_processor/diff_tests/parsing/chrome_metadata.out b/test/trace_processor/diff_tests/parsing/chrome_metadata.out
index 7346e41..873e349 100644
--- a/test/trace_processor/diff_tests/parsing/chrome_metadata.out
+++ b/test/trace_processor/diff_tests/parsing/chrome_metadata.out
@@ -1,9 +1,10 @@
 "id","type","name","key_type","int_value","str_value"
-0,"metadata","trace_uuid","single","[NULL]","00000000-0000-0000-dcce-849205cfb03e"
-1,"metadata","cr-playstore_version_code","single",101,"[NULL]"
-2,"metadata","cr-enabled_categories","single","[NULL]","cat1,cat2,cat3"
-3,"metadata","cr-background_tracing_metadata","single","[NULL]","CgUlDsAbXx2RziSz"
-4,"metadata","cr-scenario_name_hash","single",3005533841,"[NULL]"
-5,"metadata","cr-triggered_rule_name_hash","single",1595654158,"[NULL]"
-6,"metadata","trace_size_bytes","single",64,"[NULL]"
-7,"metadata","trace_type","single","[NULL]","proto"
+0,"metadata","trace_uuid","single","[NULL]","00000000-0000-0000-dcce-849205cfb03e" 
+1,"metadata","trace_time_clock_id","single",6,"[NULL]"
+2,"metadata","cr-playstore_version_code","single",101,"[NULL]"
+3,"metadata","cr-enabled_categories","single","[NULL]","cat1,cat2,cat3"
+4,"metadata","cr-background_tracing_metadata","single","[NULL]","CgUlDsAbXx2RziSz"
+5,"metadata","cr-scenario_name_hash","single",3005533841,"[NULL]"
+6,"metadata","cr-triggered_rule_name_hash","single",1595654158,"[NULL]"
+7,"metadata","trace_size_bytes","single",64,"[NULL]"
+8,"metadata","trace_type","single","[NULL]","proto"
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index c0fdd2c..b9f4ad0 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -339,7 +339,7 @@
     for (; it.valid(); it.next()) {
       const kind = ASYNC_SLICE_TRACK_KIND;
       const rawName = it.name === null ? undefined : it.name;
-      const rawParentName = it.parentName === null ? undefined : it.name;
+      const rawParentName = it.parentName === null ? undefined : it.parentName;
       const name = TrackDecider.getTrackName({name: rawName, kind});
       const rawTrackIds = it.trackIds;
       const trackIds = rawTrackIds.split(',').map((v) => Number(v));