Remove PacketSequenceState

Rename PacketSequenceState to PacketSequenceStateBuilder and hide it
in the ProtoTraceReader. Only this class should use it.

Make it more clear what state is keep around and what state is reset
for the various sequence events (packet loss, incremental state
cleared, etc).

This also gives us tow different API surfaces one for ProtoTraceReader
instances to update the incremental state as packets are porcessed in
sequence order: PacketSeqeunceStateBuilder, and another "read only" API
to be used by tokenizers and parsers of concrete trace packets.

Change-Id: I64981bddd2058e48b6e4d9bd3095a4c0bb41063e
diff --git a/Android.bp b/Android.bp
index ae8225d..4196a57 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12370,6 +12370,7 @@
         "src/trace_processor/importers/proto/stack_profile_sequence_state.cc",
         "src/trace_processor/importers/proto/track_event_module.cc",
         "src/trace_processor/importers/proto/track_event_parser.cc",
+        "src/trace_processor/importers/proto/track_event_sequence_state.cc",
         "src/trace_processor/importers/proto/track_event_tokenizer.cc",
         "src/trace_processor/importers/proto/track_event_tracker.cc",
     ],
diff --git a/BUILD b/BUILD
index 5fac4da..7078da7 100644
--- a/BUILD
+++ b/BUILD
@@ -1878,7 +1878,7 @@
         "src/trace_processor/importers/proto/network_trace_module.h",
         "src/trace_processor/importers/proto/packet_analyzer.cc",
         "src/trace_processor/importers/proto/packet_analyzer.h",
-        "src/trace_processor/importers/proto/packet_sequence_state.h",
+        "src/trace_processor/importers/proto/packet_sequence_state_builder.h",
         "src/trace_processor/importers/proto/packet_sequence_state_generation.cc",
         "src/trace_processor/importers/proto/perf_sample_tracker.cc",
         "src/trace_processor/importers/proto/perf_sample_tracker.h",
@@ -1888,7 +1888,6 @@
         "src/trace_processor/importers/proto/profile_packet_sequence_state.h",
         "src/trace_processor/importers/proto/profile_packet_utils.cc",
         "src/trace_processor/importers/proto/profile_packet_utils.h",
-        "src/trace_processor/importers/proto/proto_incremental_state.h",
         "src/trace_processor/importers/proto/proto_trace_parser_impl.cc",
         "src/trace_processor/importers/proto/proto_trace_parser_impl.h",
         "src/trace_processor/importers/proto/proto_trace_reader.cc",
@@ -1901,6 +1900,7 @@
         "src/trace_processor/importers/proto/track_event_module.h",
         "src/trace_processor/importers/proto/track_event_parser.cc",
         "src/trace_processor/importers/proto/track_event_parser.h",
+        "src/trace_processor/importers/proto/track_event_sequence_state.cc",
         "src/trace_processor/importers/proto/track_event_tokenizer.cc",
         "src/trace_processor/importers/proto/track_event_tokenizer.h",
         "src/trace_processor/importers/proto/track_event_tracker.cc",
@@ -1913,6 +1913,7 @@
     name = "src_trace_processor_importers_proto_packet_sequence_state_generation_hdr",
     srcs = [
         "src/trace_processor/importers/proto/packet_sequence_state_generation.h",
+        "src/trace_processor/importers/proto/track_event_sequence_state.h",
     ],
 )
 
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index 18a617a..dde995c 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -40,7 +40,7 @@
     "network_trace_module.h",
     "packet_analyzer.cc",
     "packet_analyzer.h",
-    "packet_sequence_state.h",
+    "packet_sequence_state_builder.h",
     "packet_sequence_state_generation.cc",
     "perf_sample_tracker.cc",
     "perf_sample_tracker.h",
@@ -50,7 +50,6 @@
     "profile_packet_sequence_state.h",
     "profile_packet_utils.cc",
     "profile_packet_utils.h",
-    "proto_incremental_state.h",
     "proto_trace_parser_impl.cc",
     "proto_trace_parser_impl.h",
     "proto_trace_reader.cc",
@@ -63,6 +62,7 @@
     "track_event_module.h",
     "track_event_parser.cc",
     "track_event_parser.h",
+    "track_event_sequence_state.cc",
     "track_event_tokenizer.cc",
     "track_event_tokenizer.h",
     "track_event_tracker.cc",
@@ -70,7 +70,6 @@
   ]
   public_deps = [ ":proto_importer_module" ]
   deps = [
-    ":packet_sequence_state_generation_hdr",
     "../../../../gn:default_deps",
     "../../../../include/perfetto/trace_processor:trace_processor",
     "../../../../protos/perfetto/common:zero",
@@ -201,6 +200,7 @@
     "proto_importer_module.cc",
     "proto_importer_module.h",
   ]
+  public_deps = [ ":packet_sequence_state_generation_hdr" ]
   deps = [
     ":packet_sequence_state_generation_hdr",
     "../../../../gn:default_deps",
@@ -212,12 +212,16 @@
 }
 
 source_set("packet_sequence_state_generation_hdr") {
-  sources = [ "packet_sequence_state_generation.h" ]
+  sources = [
+    "packet_sequence_state_generation.h",
+    "track_event_sequence_state.h",
+  ]
   deps = [
     "../../../../gn:default_deps",
     "../../../../include/perfetto/ext/base",
     "../../../../protos/perfetto/trace:non_minimal_zero",
     "../../../../protos/perfetto/trace/track_event:zero",
+    "../../types:types",
     "../../util:interned_message_view",
   ]
 }
@@ -262,6 +266,7 @@
   deps = [
     ":full",
     ":minimal",
+    ":packet_sequence_state_generation_hdr",
     "../../../../gn:default_deps",
     "../../../../gn:gtest_and_gmock",
     "../../../../protos/perfetto/common:cpp",
diff --git a/src/trace_processor/importers/proto/frame_timeline_event_parser.h b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
index 596f415..b1c1e12 100644
--- a/src/trace_processor/importers/proto/frame_timeline_event_parser.h
+++ b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
@@ -20,7 +20,6 @@
 #include "perfetto/protozero/field.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/proto/proto_incremental_state.h"
 #include "src/trace_processor/storage/trace_storage.h"
 
 #include "protos/perfetto/trace/android/frame_timeline_event.pbzero.h"
diff --git a/src/trace_processor/importers/proto/gpu_event_parser.h b/src/trace_processor/importers/proto/gpu_event_parser.h
index e2eaac8..6ca6527 100644
--- a/src/trace_processor/importers/proto/gpu_event_parser.h
+++ b/src/trace_processor/importers/proto/gpu_event_parser.h
@@ -25,7 +25,6 @@
 #include "protos/perfetto/trace/android/gpu_mem_event.pbzero.h"
 #include "protos/perfetto/trace/gpu/gpu_render_stage_event.pbzero.h"
 #include "src/trace_processor/importers/common/args_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
 #include "src/trace_processor/importers/proto/vulkan_memory_tracker.h"
 #include "src/trace_processor/storage/trace_storage.h"
 
diff --git a/src/trace_processor/importers/proto/graphics_frame_event_parser.h b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
index 2d37612..146d126 100644
--- a/src/trace_processor/importers/proto/graphics_frame_event_parser.h
+++ b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
@@ -23,7 +23,6 @@
 #include "perfetto/ext/base/string_writer.h"
 #include "perfetto/protozero/field.h"
 #include "src/trace_processor/importers/common/args_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
 #include "src/trace_processor/importers/proto/vulkan_memory_tracker.h"
 #include "src/trace_processor/storage/trace_storage.h"
 
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
deleted file mode 100644
index b50af20..0000000
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2019 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 SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/compiler.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/interned_message_view.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class PacketSequenceState {
- public:
-  explicit PacketSequenceState(TraceProcessorContext* context)
-      : context_(context) {
-    current_generation_.reset(new PacketSequenceStateGeneration(this));
-  }
-
-  int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
-    PERFETTO_DCHECK(track_event_timestamps_valid());
-    track_event_timestamp_ns_ += delta_ns;
-    return track_event_timestamp_ns_;
-  }
-
-  int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
-    PERFETTO_DCHECK(track_event_timestamps_valid());
-    track_event_thread_timestamp_ns_ += delta_ns;
-    return track_event_thread_timestamp_ns_;
-  }
-
-  int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
-    PERFETTO_DCHECK(track_event_timestamps_valid());
-    track_event_thread_instruction_count_ += delta;
-    return track_event_thread_instruction_count_;
-  }
-
-  // Intern a message into the current generation.
-  void InternMessage(uint32_t field_id, TraceBlobView message) {
-    current_generation_->InternMessage(field_id, std::move(message));
-  }
-
-  // Set the trace packet defaults for the current generation. If the current
-  // generation already has defaults set, starts a new generation without
-  // invalidating other incremental state (such as interned data).
-  void UpdateTracePacketDefaults(TraceBlobView defaults) {
-    if (!current_generation_->GetTracePacketDefaultsView()) {
-      current_generation_->SetTracePacketDefaults(std::move(defaults));
-      return;
-    }
-
-    // The new defaults should only apply to subsequent messages on the
-    // sequence. Add a new generation with the updated defaults but the
-    // current generation's interned data state.
-    current_generation_.reset(new PacketSequenceStateGeneration(
-        this, current_generation_.get(), std::move(defaults)));
-  }
-
-  void SetThreadDescriptor(int32_t pid,
-                           int32_t tid,
-                           int64_t timestamp_ns,
-                           int64_t thread_timestamp_ns,
-                           int64_t thread_instruction_count) {
-    track_event_timestamps_valid_ = true;
-    pid_and_tid_valid_ = true;
-    pid_ = pid;
-    tid_ = tid;
-    track_event_timestamp_ns_ = timestamp_ns;
-    track_event_thread_timestamp_ns_ = thread_timestamp_ns;
-    track_event_thread_instruction_count_ = thread_instruction_count;
-  }
-
-  void OnPacketLoss() {
-    packet_loss_ = true;
-    track_event_timestamps_valid_ = false;
-  }
-
-  // Starts a new generation with clean-slate incremental state and defaults.
-  void OnIncrementalStateCleared() {
-    packet_loss_ = false;
-    current_generation_.reset(new PacketSequenceStateGeneration(this));
-  }
-
-  bool IsIncrementalStateValid() const { return !packet_loss_; }
-
-  // Returns a ref-counted ptr to the current generation.
-  RefPtr<PacketSequenceStateGeneration> current_generation() const {
-    return current_generation_;
-  }
-
-  bool track_event_timestamps_valid() const {
-    return track_event_timestamps_valid_;
-  }
-
-  bool pid_and_tid_valid() const { return pid_and_tid_valid_; }
-
-  int32_t pid() const { return pid_; }
-  int32_t tid() const { return tid_; }
-
-  TraceProcessorContext* context() const { return context_; }
-
- private:
-  TraceProcessorContext* context_;
-
-  // If true, incremental state on the sequence is considered invalid until we
-  // see the next packet with incremental_state_cleared. We assume that we
-  // missed some packets at the beginning of the trace.
-  bool packet_loss_ = true;
-
-  // We can only consider TrackEvent delta timestamps to be correct after we
-  // have observed a thread descriptor (since the last packet loss).
-  bool track_event_timestamps_valid_ = false;
-
-  // |pid_| and |tid_| are only valid after we parsed at least one
-  // ThreadDescriptor packet on the sequence.
-  bool pid_and_tid_valid_ = false;
-
-  // Process/thread ID of the packet sequence set by a ThreadDescriptor
-  // packet. Used as default values for TrackEvents that don't specify a
-  // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
-  int32_t pid_ = 0;
-  int32_t tid_ = 0;
-
-  // Current wall/thread timestamps/counters used as reference for the next
-  // TrackEvent delta timestamp.
-  int64_t track_event_timestamp_ns_ = 0;
-  int64_t track_event_thread_timestamp_ns_ = 0;
-  int64_t track_event_thread_instruction_count_ = 0;
-
-  RefPtr<PacketSequenceStateGeneration> current_generation_;
-};
-
-}  // namespace trace_processor
-}  // namespace perfetto
-
-#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_builder.h b/src/trace_processor/importers/proto/packet_sequence_state_builder.h
new file mode 100644
index 0000000..599b03d
--- /dev/null
+++ b/src/trace_processor/importers/proto/packet_sequence_state_builder.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 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 SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
+
+#include <cstdint>
+
+#include "perfetto/trace_processor/ref_counted.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Helper class to generate a stream of PacketSequenceStateGeneration as we
+// receive packets for a sequence. This class deals with various events that
+// incrementally build up state that can be accessed by packet handling code
+// (tokenization nad parsing). An example of such state are interned messages or
+// trace packet defaults.
+class PacketSequenceStateBuilder {
+ public:
+  explicit PacketSequenceStateBuilder(TraceProcessorContext* context) {
+    generation_ = PacketSequenceStateGeneration::CreateFirst(context);
+  }
+
+  // Intern a message into the current generation.
+  void InternMessage(uint32_t field_id, TraceBlobView message) {
+    generation_->InternMessage(field_id, std::move(message));
+  }
+
+  // Set the trace packet defaults for the current generation. If the current
+  // generation already has defaults set, starts a new generation without
+  // invalidating other incremental state (such as interned data).
+  void UpdateTracePacketDefaults(TraceBlobView defaults) {
+    generation_ = generation_->OnNewTracePacketDefaults(std::move(defaults));
+  }
+
+  void OnPacketLoss() {
+    generation_ = generation_->OnPacketLoss();
+    packet_loss_ = true;
+  }
+
+  // Starts a new generation with clean-slate incremental state and defaults.
+  void OnIncrementalStateCleared() {
+    packet_loss_ = false;
+    generation_ = generation_->OnIncrementalStateCleared();
+  }
+
+  bool IsIncrementalStateValid() const { return !packet_loss_; }
+
+  // Returns a ref-counted ptr to the current generation.
+  RefPtr<PacketSequenceStateGeneration> current_generation() const {
+    return generation_;
+  }
+
+ private:
+  // If true, incremental state on the sequence is considered invalid until we
+  // see the next packet with incremental_state_cleared. We assume that we
+  // missed some packets at the beginning of the trace.
+  bool packet_loss_ = true;
+
+  RefPtr<PacketSequenceStateGeneration> generation_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
index c520e92..711bb64 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
@@ -17,42 +17,89 @@
 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include <cstddef>
 
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/track_event_sequence_state.h"
+#include "src/trace_processor/storage/stats.h"
 #include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
 
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
+
+PacketSequenceStateGeneration::CustomState::~CustomState() = default;
+
+// static
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::CreateFirst(TraceProcessorContext* context) {
+  return RefPtr<PacketSequenceStateGeneration>(
+      new PacketSequenceStateGeneration(
+          context, TrackEventSequenceState::CreateFirst(), false));
+}
 
 PacketSequenceStateGeneration::PacketSequenceStateGeneration(
-    PacketSequenceState* state,
-    PacketSequenceStateGeneration* prev_gen,
-    TraceBlobView defaults)
-    : state_(state),
-      interned_data_(prev_gen->interned_data_),
-      trace_packet_defaults_(InternedMessageView(std::move(defaults))),
-      trackers_(prev_gen->trackers_) {
-  for (auto& t : trackers_) {
-    if (t.get() != nullptr) {
-      t->set_generation(this);
+    TraceProcessorContext* context,
+    InternedFieldMap interned_data,
+    TrackEventSequenceState track_event_sequence_state,
+    CustomStateArray custom_state,
+    TraceBlobView trace_packet_defaults,
+    bool is_incremental_state_valid)
+    : context_(context),
+      interned_data_(std::move(interned_data)),
+      track_event_sequence_state_(std::move(track_event_sequence_state)),
+      custom_state_(std::move(custom_state)),
+      trace_packet_defaults_(std::move(trace_packet_defaults)),
+      is_incremental_state_valid_(is_incremental_state_valid) {
+  for (auto& s : custom_state_) {
+    if (s.get() != nullptr) {
+      s->set_generation(this);
     }
   }
 }
 
-PacketSequenceStateGeneration::InternedDataTracker::~InternedDataTracker() =
-    default;
-
-bool PacketSequenceStateGeneration::pid_and_tid_valid() const {
-  return state_->pid_and_tid_valid();
-}
-int32_t PacketSequenceStateGeneration::pid() const {
-  return state_->pid();
-}
-int32_t PacketSequenceStateGeneration::tid() const {
-  return state_->tid();
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnPacketLoss() {
+  // No need to increment the generation. If any future packet depends on
+  // previous messages to update the incremental state its packet (if the
+  // DataSource is behaving correctly) would have the
+  // SEQ_NEEDS_INCREMENTAL_STATE bit set and such a packet will be dropped by
+  // the ProtoTraceReader and never make it far enough to update any incremental
+  // state.
+  track_event_sequence_state_.OnPacketLoss();
+  is_incremental_state_valid_ = false;
+  return RefPtr<PacketSequenceStateGeneration>(this);
 }
 
-TraceProcessorContext* PacketSequenceStateGeneration::GetContext() const {
-  return state_->context();
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnIncrementalStateCleared() {
+  return RefPtr<PacketSequenceStateGeneration>(
+      new PacketSequenceStateGeneration(
+          context_, track_event_sequence_state_.OnIncrementalStateCleared(),
+          true));
+}
+
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnNewTracePacketDefaults(
+    TraceBlobView trace_packet_defaults) {
+  return RefPtr<PacketSequenceStateGeneration>(
+      new PacketSequenceStateGeneration(
+          context_, interned_data_,
+          track_event_sequence_state_.OnIncrementalStateCleared(),
+          custom_state_, std::move(trace_packet_defaults),
+          is_incremental_state_valid_));
+}
+
+InternedMessageView* PacketSequenceStateGeneration::GetInternedMessageView(
+    uint32_t field_id,
+    uint64_t iid) {
+  auto field_it = interned_data_.find(field_id);
+  if (field_it != interned_data_.end()) {
+    auto* message_map = &field_it->second;
+    auto it = message_map->find(iid);
+    if (it != message_map->end()) {
+      return &it->second;
+    }
+  }
+
+  context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
+  return nullptr;
 }
 
 void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
@@ -67,8 +114,7 @@
   auto field = decoder.FindField(kIidFieldNumber);
   if (PERFETTO_UNLIKELY(!field)) {
     PERFETTO_DLOG("Interned message without interning_id");
-    state_->context()->storage->IncrementStats(
-        stats::interned_data_tokenizer_errors);
+    context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
     return;
   }
   iid = field.as_uint64();
@@ -87,51 +133,4 @@
                           message_size) == 0));
 }
 
-InternedMessageView* PacketSequenceStateGeneration::GetInternedMessageView(
-    uint32_t field_id,
-    uint64_t iid) {
-  auto field_it = interned_data_.find(field_id);
-  if (field_it != interned_data_.end()) {
-    auto* message_map = &field_it->second;
-    auto it = message_map->find(iid);
-    if (it != message_map->end()) {
-      return &it->second;
-    }
-  }
-  state_->context()->storage->IncrementStats(
-      stats::interned_data_tokenizer_errors);
-  return nullptr;
-}
-
-int64_t PacketSequenceStateGeneration::IncrementAndGetTrackEventTimeNs(
-    int64_t delta_ns) {
-  return state_->IncrementAndGetTrackEventTimeNs(delta_ns);
-}
-int64_t PacketSequenceStateGeneration::IncrementAndGetTrackEventThreadTimeNs(
-    int64_t delta_ns) {
-  return state_->IncrementAndGetTrackEventThreadTimeNs(delta_ns);
-}
-int64_t
-PacketSequenceStateGeneration::IncrementAndGetTrackEventThreadInstructionCount(
-    int64_t delta) {
-  return state_->IncrementAndGetTrackEventThreadInstructionCount(delta);
-}
-bool PacketSequenceStateGeneration::track_event_timestamps_valid() const {
-  return state_->track_event_timestamps_valid();
-}
-void PacketSequenceStateGeneration::SetThreadDescriptor(
-    int32_t pid,
-    int32_t tid,
-    int64_t timestamp_ns,
-    int64_t thread_timestamp_ns,
-    int64_t thread_instruction_count) {
-  state_->SetThreadDescriptor(pid, tid, timestamp_ns, thread_timestamp_ns,
-                              thread_instruction_count);
-}
-
-bool PacketSequenceStateGeneration::IsIncrementalStateValid() const {
-  return state_->IsIncrementalStateValid();
-}
-
-}  // namespace trace_processor
-}  // namespace perfetto
+}  // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.h b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
index 6b60b59..82e2252 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
@@ -17,21 +17,16 @@
 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
 #define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
 
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
 #include <optional>
-#include <tuple>
-#include <type_traits>
 #include <unordered_map>
 
-#include "perfetto/public/compiler.h"
 #include "perfetto/trace_processor/ref_counted.h"
 #include "perfetto/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/importers/proto/track_event_sequence_state.h"
 #include "src/trace_processor/util/interned_message_view.h"
 
 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
 
 namespace perfetto {
@@ -42,32 +37,36 @@
 using InternedFieldMap =
     std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
 
-class PacketSequenceState;
 class TraceProcessorContext;
 
 class StackProfileSequenceState;
 class ProfilePacketSequenceState;
 class V8SequenceState;
 
-using InternedDataTrackers = std::tuple<StackProfileSequenceState,
-                                        ProfilePacketSequenceState,
-                                        V8SequenceState>;
+using CustomStateClasses = std::tuple<StackProfileSequenceState,
+                                      ProfilePacketSequenceState,
+                                      V8SequenceState>;
 
+// This is the public API exposed to packet tokenizers and parsers to access
+// state attached to a packet sequence. This state evolves as packets are
+// processed in sequence order. A packet that requires sequence state to be
+// properly parsed should snapshot this state by taking a copy of the RefPtr to
+// the currently active generation and passing it along with parsing specific
+// data to the sorting stage.
 class PacketSequenceStateGeneration : public RefCounted {
  public:
-  // Base class to add custom sequence state. This state is keep per sequence
-  // and per incremental state interval, that is, each time incremental state is
-  // reset a new instance is created but not each time `TracePacketDefaults` are
-  // updated. Note that this means that different
+  // Base class to attach custom state to the sequence state. This state is keep
+  // per sequence and per incremental state interval, that is, each time
+  // incremental state is reset a new instance is created but not each time
+  // `TracePacketDefaults` are updated. Note that this means that different
   // `PacketSequenceStateGeneration` instances might point to the same
-  // `InternedDataTracker` (because they only differ in their
-  // `TracePacketDefaults`).
+  // `CustomState` (because they only differ in their `TracePacketDefaults`).
   //
   // ATTENTION: You should not create instances of these classes yourself but
-  // use the `PacketSequenceStateGeneration::GetOrCreate<>' method instead.
-  class InternedDataTracker : public RefCounted {
+  // use the `PacketSequenceStateGeneration::GetCustomState<>' method instead.
+  class CustomState : public RefCounted {
    public:
-    virtual ~InternedDataTracker();
+    virtual ~CustomState();
 
    protected:
     template <uint32_t FieldId, typename MessageType>
@@ -81,8 +80,8 @@
     }
 
     template <typename T>
-    std::remove_cv_t<T>* GetOrCreate() {
-      return generation_->GetOrCreate<T>();
+    std::remove_cv_t<T>* GetCustomState() {
+      return generation_->GetCustomState<T>();
     }
 
     bool pid_and_tid_valid() const { return generation_->pid_and_tid_valid(); }
@@ -103,32 +102,57 @@
     // point to the latest one. We keep this member private to prevent misuse /
     // confusion around this fact. Instead subclasses should access the public
     // methods of this class to get any interned data.
+    // TODO(carlscab): Given that CustomState is ref counted this pointer might
+    // become invalid. CustomState should not be ref pointed and instead be
+    // owned by the `PacketSequenceStateGeneration` instance pointed at by
+    // `generation_`.
     PacketSequenceStateGeneration* generation_ = nullptr;
   };
 
-  bool pid_and_tid_valid() const;
-  int32_t pid() const;
-  int32_t tid() const;
+  static RefPtr<PacketSequenceStateGeneration> CreateFirst(
+      TraceProcessorContext* context);
+
+  RefPtr<PacketSequenceStateGeneration> OnPacketLoss();
+
+  RefPtr<PacketSequenceStateGeneration> OnIncrementalStateCleared();
+
+  RefPtr<PacketSequenceStateGeneration> OnNewTracePacketDefaults(
+      TraceBlobView trace_packet_defaults);
+
+  bool pid_and_tid_valid() const {
+    return track_event_sequence_state_.pid_and_tid_valid();
+  }
+  int32_t pid() const { return track_event_sequence_state_.pid(); }
+  int32_t tid() const { return track_event_sequence_state_.tid(); }
 
   // Returns |nullptr| if the message with the given |iid| was not found (also
   // records a stat in this case).
   template <uint32_t FieldId, typename MessageType>
-  typename MessageType::Decoder* LookupInternedMessage(uint64_t iid);
+  typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
+    auto* interned_message_view = GetInternedMessageView(FieldId, iid);
+    if (!interned_message_view)
+      return nullptr;
+
+    return interned_message_view->template GetOrCreateDecoder<MessageType>();
+  }
 
   InternedMessageView* GetInternedMessageView(uint32_t field_id, uint64_t iid);
   // Returns |nullptr| if no defaults were set.
   InternedMessageView* GetTracePacketDefaultsView() {
-    if (!trace_packet_defaults_)
+    if (!trace_packet_defaults_.has_value()) {
       return nullptr;
-    return &trace_packet_defaults_.value();
+    }
+
+    return &*trace_packet_defaults_;
   }
 
   // Returns |nullptr| if no defaults were set.
   protos::pbzero::TracePacketDefaults::Decoder* GetTracePacketDefaults() {
-    InternedMessageView* view = GetTracePacketDefaultsView();
-    if (!view)
+    if (!trace_packet_defaults_.has_value()) {
       return nullptr;
-    return view->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
+    }
+    return trace_packet_defaults_
+        ->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
   }
 
   // Returns |nullptr| if no TrackEventDefaults were set.
@@ -148,30 +172,57 @@
     return nullptr;
   }
 
-  // Extension point for custom sequence state. To add new per sequence state
-  // just subclass ´PacketSequenceStateGeneration´ and get your sequence bound
-  // instance by calling this method.
+  // Extension point for custom incremental state. Custom state classes need to
+  // inherit from `CustomState`.
+  //
+  // A common use case for this custom state is to store cache mappings between
+  // interning ids (iid) and TraceProcessor objects (e.g. table row). When we
+  // see an iid we need to access the InternedMessageView for that iid, and
+  // possibly do some computations, the result of all of this could then be
+  // cached so that next time we encounter the same iid we could reuse this
+  // cached value. This caching is only valid until incremental state is
+  // cleared, from then on subsequent iid values on the sequence will no longer
+  // refer to the same entities as the iid values before the clear. Custom state
+  // classes no not need to explicitly handle this: they are attached to an
+  // `IncrementalState` instance, and a new one is created when the state is
+  // cleared, so iid values after the clear will be processed by a new (empty)
+  // custom state instance.
   template <typename T>
-  std::remove_cv_t<T>* GetOrCreate();
+  std::remove_cv_t<T>* GetCustomState();
 
-  // TODO(carlscab): All this should be tracked in a dedicated class
-  // TrackEventSequenceState or something attached to the "incremental state".
-  int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns);
-  int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns);
-  int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta);
-  bool track_event_timestamps_valid() const;
-  void SetThreadDescriptor(int32_t pid,
-                           int32_t tid,
-                           int64_t timestamp_ns,
-                           int64_t thread_timestamp_ns,
-                           int64_t thread_instruction_count);
+  int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
+    return track_event_sequence_state_.IncrementAndGetTrackEventTimeNs(
+        delta_ns);
+  }
+
+  int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
+    return track_event_sequence_state_.IncrementAndGetTrackEventThreadTimeNs(
+        delta_ns);
+  }
+
+  int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
+    return track_event_sequence_state_
+        .IncrementAndGetTrackEventThreadInstructionCount(delta);
+  }
+
+  bool track_event_timestamps_valid() const {
+    return track_event_sequence_state_.timestamps_valid();
+  }
+
+  void SetThreadDescriptor(
+      const protos::pbzero::ThreadDescriptor::Decoder& descriptor) {
+    track_event_sequence_state_.SetThreadDescriptor(descriptor);
+  }
 
   // TODO(carlscab): Nobody other than `ProtoTraceReader` should care about
   // this. Remove.
-  bool IsIncrementalStateValid() const;
+  bool IsIncrementalStateValid() const { return is_incremental_state_valid_; }
 
  private:
-  friend class PacketSequenceState;
+  friend class PacketSequenceStateBuilder;
+
+  using CustomStateArray =
+      std::array<RefPtr<CustomState>, std::tuple_size_v<CustomStateClasses>>;
 
   // Helper to find the index in a tuple of a given type. Lookups are done
   // ignoring cv qualifiers. If no index is found size of the tuple is returned.
@@ -195,56 +246,50 @@
     }
   }
 
-  explicit PacketSequenceStateGeneration(PacketSequenceState* state)
-      : state_(state) {}
+  PacketSequenceStateGeneration(TraceProcessorContext* context,
+                                TrackEventSequenceState track_state,
+                                bool is_incremental_state_valid)
+      : context_(context),
+        track_event_sequence_state_(std::move(track_state)),
+        is_incremental_state_valid_(is_incremental_state_valid) {}
 
-  PacketSequenceStateGeneration(PacketSequenceState* state,
-                                PacketSequenceStateGeneration* prev_gen,
-                                TraceBlobView defaults);
+  PacketSequenceStateGeneration(
+      TraceProcessorContext* context,
+      InternedFieldMap interned_data,
+      TrackEventSequenceState track_event_sequence_state,
+      CustomStateArray custom_state,
+      TraceBlobView trace_packet_defaults,
+      bool is_incremental_state_valid);
 
-  TraceProcessorContext* GetContext() const;
-
+  // Add an interned message to this incremental state view. This can only be
+  // called by `PacketSequenceStateBuilder' (which is a friend) as packet
+  // tokenizers and parsers should never deal directly with reading interned
+  // data out of trace packets.
   void InternMessage(uint32_t field_id, TraceBlobView message);
 
-  void SetTracePacketDefaults(TraceBlobView defaults) {
-    // Defaults should only be set once per generation.
-    PERFETTO_DCHECK(!trace_packet_defaults_);
-    trace_packet_defaults_ = InternedMessageView(std::move(defaults));
-  }
-
-  // TODO(carlscab): This is dangerous given that PacketSequenceStateGeneration
-  // is refcounted and PacketSequenceState is not.
-  PacketSequenceState* state_;
+  TraceProcessorContext* const context_;
   InternedFieldMap interned_data_;
+  TrackEventSequenceState track_event_sequence_state_;
+  CustomStateArray custom_state_;
   std::optional<InternedMessageView> trace_packet_defaults_;
-  std::array<RefPtr<InternedDataTracker>,
-             std::tuple_size_v<InternedDataTrackers>>
-      trackers_;
+  // TODO(carlscab): Should not be needed as clients of this class should not
+  // care about validity.
+  bool is_incremental_state_valid_ = true;
 };
 
 template <typename T>
-std::remove_cv_t<T>* PacketSequenceStateGeneration::GetOrCreate() {
-  constexpr size_t index = FindUniqueType<InternedDataTrackers, T>();
-  static_assert(index < std::tuple_size_v<InternedDataTrackers>, "Not found");
-  auto& ptr = trackers_[index];
+std::remove_cv_t<T>* PacketSequenceStateGeneration::GetCustomState() {
+  constexpr size_t index = FindUniqueType<CustomStateClasses, T>();
+  static_assert(index < std::tuple_size_v<CustomStateClasses>, "Not found");
+  auto& ptr = custom_state_[index];
   if (PERFETTO_UNLIKELY(ptr.get() == nullptr)) {
-    ptr.reset(new T(GetContext()));
+    ptr.reset(new T(context_));
     ptr->set_generation(this);
   }
 
   return static_cast<std::remove_cv_t<T>*>(ptr.get());
 }
 
-template <uint32_t FieldId, typename MessageType>
-typename MessageType::Decoder*
-PacketSequenceStateGeneration::LookupInternedMessage(uint64_t iid) {
-  auto* interned_message_view = GetInternedMessageView(FieldId, iid);
-  if (!interned_message_view)
-    return nullptr;
-
-  return interned_message_view->template GetOrCreateDecoder<MessageType>();
-}
-
 }  // namespace trace_processor
 }  // namespace perfetto
 
diff --git a/src/trace_processor/importers/proto/profile_module.cc b/src/trace_processor/importers/proto/profile_module.cc
index 6064d33..42578ae 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -155,7 +155,7 @@
   ProcessTracker* procs = context_->process_tracker.get();
   TraceStorage* storage = context_->storage.get();
   StackProfileSequenceState& stack_profile_sequence_state =
-      *sequence_state->GetOrCreate<StackProfileSequenceState>();
+      *sequence_state->GetCustomState<StackProfileSequenceState>();
 
   uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
   uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
@@ -255,7 +255,7 @@
       context_->process_tracker->GetOrCreateProcess(sample.pid());
 
   StackProfileSequenceState& stack_profile_sequence_state =
-      *sequence_state->GetOrCreate<StackProfileSequenceState>();
+      *sequence_state->GetCustomState<StackProfileSequenceState>();
   uint64_t callstack_iid = sample.callstack_iid();
   std::optional<CallsiteId> cs_id =
       stack_profile_sequence_state.FindOrInsertCallstack(upid, callstack_iid);
@@ -306,7 +306,7 @@
     PacketSequenceStateGeneration* sequence_state,
     ConstBytes blob) {
   ProfilePacketSequenceState& profile_packet_sequence_state =
-      *sequence_state->GetOrCreate<ProfilePacketSequenceState>();
+      *sequence_state->GetCustomState<ProfilePacketSequenceState>();
   protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
   profile_packet_sequence_state.SetProfilePacketIndex(packet.index());
 
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
index b5cdb70..f0858e3 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
@@ -283,8 +283,8 @@
   if (CallsiteId* id = callstacks_.Find(iid); id) {
     return *id;
   }
-  return GetOrCreate<StackProfileSequenceState>()->FindOrInsertCallstack(upid,
-                                                                         iid);
+  return GetCustomState<StackProfileSequenceState>()->FindOrInsertCallstack(
+      upid, iid);
 }
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.h b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
index 3fb8dcd..7282657 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
@@ -34,7 +34,7 @@
 
 // Keeps sequence specific state for profile packets.
 class ProfilePacketSequenceState final
-    : public PacketSequenceStateGeneration::InternedDataTracker {
+    : public PacketSequenceStateGeneration::CustomState {
  public:
   using SourceStringId = uint64_t;
 
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
index c9cd6e3..ddaaa85 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
@@ -20,7 +20,7 @@
 
 #include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 #include "test/gtest_and_gmock.h"
 
@@ -61,7 +61,7 @@
     context.storage.reset(new TraceStorage());
     context.mapping_tracker.reset(new MappingTracker(&context));
     context.stack_profile_tracker.reset(new StackProfileTracker(&context));
-    packet_sequence_state.reset(new PacketSequenceState(&context));
+    sequence_state = PacketSequenceStateGeneration::CreateFirst(&context);
 
     mapping_name = context.storage->InternString("[mapping]");
     fully_qualified_mapping_name = context.storage->InternString("/[mapping]");
@@ -71,8 +71,7 @@
 
  protected:
   ProfilePacketSequenceState& profile_packet_sequence_state() {
-    return *packet_sequence_state->current_generation()
-                ->GetOrCreate<ProfilePacketSequenceState>();
+    return *sequence_state->GetCustomState<ProfilePacketSequenceState>();
   }
   void InsertMapping(const Packet& packet) {
     profile_packet_sequence_state().AddString(packet.mapping_name_id,
@@ -117,7 +116,7 @@
   StringId build;
   StringId frame_name;
   TraceProcessorContext context;
-  std::unique_ptr<PacketSequenceState> packet_sequence_state;
+  RefPtr<PacketSequenceStateGeneration> sequence_state;
 };
 
 // Insert the same mapping from two different packets, with different strings
@@ -200,9 +199,9 @@
   context.storage.reset(new TraceStorage());
   context.mapping_tracker.reset(new MappingTracker(&context));
   context.stack_profile_tracker.reset(new StackProfileTracker(&context));
-  PacketSequenceState pss(&context);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context);
   ProfilePacketSequenceState& ppss =
-      *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+      *state->GetCustomState<ProfilePacketSequenceState>();
 
   constexpr auto kBuildId = 1u;
   constexpr auto kMappingNameId1 = 2u;
@@ -235,9 +234,9 @@
   context.mapping_tracker.reset(new MappingTracker(&context));
   context.stack_profile_tracker.reset(new StackProfileTracker(&context));
 
-  PacketSequenceState pss(&context);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context);
   ProfilePacketSequenceState& ppss =
-      *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+      *state->GetCustomState<ProfilePacketSequenceState>();
 
   uint32_t next_string_intern_id = 1;
 
diff --git a/src/trace_processor/importers/proto/proto_incremental_state.h b/src/trace_processor/importers/proto/proto_incremental_state.h
deleted file mode 100644
index aaac42f..0000000
--- a/src/trace_processor/importers/proto/proto_incremental_state.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2019 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 SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
-
-#include <stdint.h>
-
-#include <map>
-
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class TraceProcessorContext;
-
-// Stores per-packet-sequence incremental state during trace parsing, such as
-// reference timestamps for delta timestamp calculation and interned messages.
-class ProtoIncrementalState {
- public:
-  ProtoIncrementalState(TraceProcessorContext* context) : context_(context) {}
-
-  // Returns the PacketSequenceState for the packet sequence with the given id.
-  // If this is a new sequence which we haven't tracked before, initializes and
-  // inserts a new PacketSequenceState into the state map.
-  PacketSequenceState* GetOrCreateStateForPacketSequence(uint32_t sequence_id) {
-    auto& ptr = packet_sequence_states_[sequence_id];
-    if (!ptr)
-      ptr.reset(new PacketSequenceState(context_));
-    return ptr.get();
-  }
-
- private:
-  // Stores unique_ptrs to ensure that pointers to a PacketSequenceState remain
-  // valid even if the map rehashes.
-  std::map<uint32_t, std::unique_ptr<PacketSequenceState>>
-      packet_sequence_states_;
-
-  TraceProcessorContext* context_;
-};
-
-}  // namespace trace_processor
-}  // namespace perfetto
-
-#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index e139cbe..2e50f0c 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -34,8 +34,6 @@
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/ftrace/ftrace_module.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"
 #include "src/trace_processor/sorter/trace_sorter.h"
 #include "src/trace_processor/storage/stats.h"
 #include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index 1243b97..a93ad98 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -19,11 +19,13 @@
 
 #include <stdint.h>
 
-#include <memory>
+#include <tuple>
+#include <utility>
 
+#include "perfetto/ext/base/flat_hash_map.h"
 #include "src/trace_processor/importers/common/chunked_trace_reader.h"
 #include "src/trace_processor/importers/proto/multi_machine_trace_manager.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_builder.h"
 #include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
 #include "src/trace_processor/storage/trace_storage.h"
 
@@ -79,11 +81,15 @@
 
   std::optional<StringId> GetBuiltinClockNameOrNull(int64_t clock_id);
 
-  PacketSequenceState* GetIncrementalStateForPacketSequence(
+  PacketSequenceStateBuilder* GetIncrementalStateForPacketSequence(
       uint32_t sequence_id) {
-    if (!incremental_state)
-      incremental_state.reset(new ProtoIncrementalState(context_));
-    return incremental_state->GetOrCreateStateForPacketSequence(sequence_id);
+    auto* builder = packet_sequence_state_builders_.Find(sequence_id);
+    if (builder == nullptr) {
+      builder = packet_sequence_state_builders_
+                    .Insert(sequence_id, PacketSequenceStateBuilder(context_))
+                    .first;
+    }
+    return builder;
   }
   util::Status ParseExtensionDescriptor(ConstBytes descriptor);
 
@@ -95,9 +101,8 @@
   // timestamp given is latest_timestamp_.
   int64_t latest_timestamp_ = 0;
 
-  // Stores incremental state and references to interned data, e.g. for track
-  // event protos.
-  std::unique_ptr<ProtoIncrementalState> incremental_state;
+  base::FlatHashMap<uint32_t, PacketSequenceStateBuilder>
+      packet_sequence_state_builders_;
 
   StringId skipped_packet_key_id_;
   StringId invalid_incremental_state_key_id_;
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.h b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
index 518388d..e946e8d 100644
--- a/src/trace_processor/importers/proto/stack_profile_sequence_state.h
+++ b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
@@ -23,7 +23,6 @@
 #include "perfetto/ext/base/flat_hash_map.h"
 #include "perfetto/ext/base/hash.h"
 #include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/types/trace_processor_context.h"
@@ -35,7 +34,7 @@
 class VirtualMemoryMapping;
 
 class StackProfileSequenceState final
-    : public PacketSequenceStateGeneration::InternedDataTracker {
+    : public PacketSequenceStateGeneration::CustomState {
  public:
   explicit StackProfileSequenceState(TraceProcessorContext* context);
 
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 09ef474..b2b4e93 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -31,6 +31,7 @@
 #include "src/trace_processor/importers/common/machine_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/common/virtual_memory_mapping.h"
 #include "src/trace_processor/importers/json/json_utils.h"
 #include "src/trace_processor/importers/proto/packet_analyzer.h"
 #include "src/trace_processor/importers/proto/profile_packet_utils.h"
@@ -197,7 +198,7 @@
   // Interned mapping_id loses it's meaning when the sequence ends. So we need
   // to get an id from stack_profile_mapping table.
   auto mapping = delegate.seq_state()
-                     ->GetOrCreate<StackProfileSequenceState>()
+                     ->GetCustomState<StackProfileSequenceState>()
                      ->FindOrInsertMapping(decoder->mapping_id());
   if (!mapping) {
     return std::nullopt;
diff --git a/src/trace_processor/importers/proto/track_event_sequence_state.cc b/src/trace_processor/importers/proto/track_event_sequence_state.cc
new file mode 100644
index 0000000..99bc93e
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_sequence_state.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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 "src/trace_processor/importers/proto/track_event_sequence_state.h"
+
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+void TrackEventSequenceState::SetThreadDescriptor(
+    const protos::pbzero::ThreadDescriptor::Decoder& decoder) {
+  persistent_state_.pid_and_tid_valid = true;
+  persistent_state_.pid = decoder.pid();
+  persistent_state_.tid = decoder.tid();
+
+  timestamps_valid_ = true;
+  timestamp_ns_ = decoder.reference_timestamp_us() * 1000;
+  thread_timestamp_ns_ = decoder.reference_thread_time_us() * 1000;
+  thread_instruction_count_ = decoder.reference_thread_instruction_count();
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/track_event_sequence_state.h b/src/trace_processor/importers/proto/track_event_sequence_state.h
new file mode 100644
index 0000000..9291ef7
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_sequence_state.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 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 SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
+
+#include <utility>
+
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TrackEventSequenceState {
+ public:
+  static TrackEventSequenceState CreateFirst() {
+    return TrackEventSequenceState(PersistentState());
+  }
+
+  TrackEventSequenceState OnIncrementalStateCleared() {
+    return TrackEventSequenceState(persistent_state_);
+  }
+
+  void OnPacketLoss() { timestamps_valid_ = false; }
+
+  bool pid_and_tid_valid() const { return persistent_state_.pid_and_tid_valid; }
+
+  int32_t pid() const { return persistent_state_.pid; }
+  int32_t tid() const { return persistent_state_.tid; }
+
+  bool timestamps_valid() const { return timestamps_valid_; }
+
+  int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
+    PERFETTO_DCHECK(timestamps_valid());
+    timestamp_ns_ += delta_ns;
+    return timestamp_ns_;
+  }
+
+  int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
+    PERFETTO_DCHECK(timestamps_valid());
+    thread_timestamp_ns_ += delta_ns;
+    return thread_timestamp_ns_;
+  }
+
+  int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
+    PERFETTO_DCHECK(timestamps_valid());
+    thread_instruction_count_ += delta;
+    return thread_instruction_count_;
+  }
+
+  void SetThreadDescriptor(const protos::pbzero::ThreadDescriptor::Decoder&);
+
+ private:
+  // State that is never cleared.
+  struct PersistentState {
+    // |pid_| and |tid_| are only valid after we parsed at least one
+    // ThreadDescriptor packet on the sequence.
+    bool pid_and_tid_valid = false;
+
+    // Process/thread ID of the packet sequence set by a ThreadDescriptor
+    // packet. Used as default values for TrackEvents that don't specify a
+    // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
+    int32_t pid = 0;
+    int32_t tid = 0;
+  };
+
+  explicit TrackEventSequenceState(PersistentState persistent_state)
+      : persistent_state_(std::move(persistent_state)) {}
+
+  // We can only consider TrackEvent delta timestamps to be correct after we
+  // have observed a thread descriptor (since the last packet loss).
+  bool timestamps_valid_ = false;
+
+  // Current wall/thread timestamps/counters used as reference for the next
+  // TrackEvent delta timestamp.
+  int64_t timestamp_ns_ = 0;
+  int64_t thread_timestamp_ns_ = 0;
+  int64_t thread_instruction_count_ = 0;
+
+  PersistentState persistent_state_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index d9ed336..c836052 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -212,10 +212,7 @@
     const protos::pbzero::ThreadDescriptor::Decoder& thread) {
   // TODO(eseckler): Remove support for legacy thread descriptor-based default
   // tracks and delta timestamps.
-  state.SetThreadDescriptor(thread.pid(), thread.tid(),
-                            thread.reference_timestamp_us() * 1000,
-                            thread.reference_thread_time_us() * 1000,
-                            thread.reference_thread_instruction_count());
+  state.SetThreadDescriptor(thread);
 }
 
 void TrackEventTokenizer::TokenizeTrackEventPacket(
diff --git a/src/trace_processor/importers/proto/v8_module.cc b/src/trace_processor/importers/proto/v8_module.cc
index 89360b6..88d8f53 100644
--- a/src/trace_processor/importers/proto/v8_module.cc
+++ b/src/trace_processor/importers/proto/v8_module.cc
@@ -142,7 +142,8 @@
 void V8Module::ParseV8JsCode(protozero::ConstBytes bytes,
                              int64_t ts,
                              const TracePacketData& data) {
-  V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+  V8SequenceState& state =
+      *data.sequence_state->GetCustomState<V8SequenceState>();
 
   V8JsCode::Decoder code(bytes);
 
@@ -169,7 +170,8 @@
 void V8Module::ParseV8InternalCode(protozero::ConstBytes bytes,
                                    int64_t ts,
                                    const TracePacketData& data) {
-  V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+  V8SequenceState& state =
+      *data.sequence_state->GetCustomState<V8SequenceState>();
 
   V8InternalCode::Decoder code(bytes);
 
@@ -190,7 +192,8 @@
 void V8Module::ParseV8WasmCode(protozero::ConstBytes bytes,
                                int64_t ts,
                                const TracePacketData& data) {
-  V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+  V8SequenceState& state =
+      *data.sequence_state->GetCustomState<V8SequenceState>();
 
   V8WasmCode::Decoder code(bytes);
 
@@ -217,7 +220,8 @@
 void V8Module::ParseV8RegExpCode(protozero::ConstBytes bytes,
                                  int64_t ts,
                                  const TracePacketData& data) {
-  V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+  V8SequenceState& state =
+      *data.sequence_state->GetCustomState<V8SequenceState>();
 
   V8RegExpCode::Decoder code(bytes);
 
@@ -238,7 +242,8 @@
 void V8Module::ParseV8CodeMove(protozero::ConstBytes bytes,
                                int64_t,
                                const TracePacketData& data) {
-  V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+  V8SequenceState& state =
+      *data.sequence_state->GetCustomState<V8SequenceState>();
   protos::pbzero::V8CodeMove::Decoder v8_code_move(bytes);
 
   std::optional<IsolateId> isolate_id =
diff --git a/src/trace_processor/importers/proto/v8_sequence_state.h b/src/trace_processor/importers/proto/v8_sequence_state.h
index d2e008a..1b60ca0 100644
--- a/src/trace_processor/importers/proto/v8_sequence_state.h
+++ b/src/trace_processor/importers/proto/v8_sequence_state.h
@@ -24,7 +24,6 @@
 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/tables/v8_tables_py.h"
-#include "src/trace_processor/types/destructible.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -34,7 +33,7 @@
 
 // Helper class to deal with V8 related interned data.
 class V8SequenceState final
-    : public PacketSequenceStateGeneration::InternedDataTracker {
+    : public PacketSequenceStateGeneration::CustomState {
  public:
   explicit V8SequenceState(TraceProcessorContext* context);
 
diff --git a/src/trace_processor/importers/proto/vulkan_memory_tracker.h b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
index 9d1afc5..dd44a89 100644
--- a/src/trace_processor/importers/proto/vulkan_memory_tracker.h
+++ b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
@@ -17,19 +17,18 @@
 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
 #define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
 
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
 
 #include "protos/perfetto/trace/gpu/vulkan_memory_event.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
 
 namespace perfetto {
 namespace trace_processor {
 
 using protos::pbzero::VulkanMemoryEvent;
 
-class TraceProcessorContext;
-
 class VulkanMemoryTracker {
  public:
   enum class DeviceCounterType {
diff --git a/src/trace_processor/sorter/BUILD.gn b/src/trace_processor/sorter/BUILD.gn
index 5d27204..8d4c9f9 100644
--- a/src/trace_processor/sorter/BUILD.gn
+++ b/src/trace_processor/sorter/BUILD.gn
@@ -50,9 +50,11 @@
     "../../../gn:default_deps",
     "../../../gn:gtest_and_gmock",
     "../../../include/perfetto/trace_processor:storage",
+    "../../../include/perfetto/trace_processor:trace_processor",
     "../../base",
     "../importers/common:parser_types",
     "../importers/proto:minimal",
+    "../importers/proto:packet_sequence_state_generation_hdr",
     "../types",
   ]
 }
diff --git a/src/trace_processor/sorter/trace_sorter.h b/src/trace_processor/sorter/trace_sorter.h
index dd38504..5ea0e0d 100644
--- a/src/trace_processor/sorter/trace_sorter.h
+++ b/src/trace_processor/sorter/trace_sorter.h
@@ -28,7 +28,6 @@
 #include "perfetto/public/compiler.h"
 #include "perfetto/trace_processor/basic_types.h"
 #include "perfetto/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/importers/common/parser_types.h"
 #include "src/trace_processor/importers/common/trace_parser.h"
 #include "src/trace_processor/importers/fuchsia/fuchsia_record.h"
 #include "src/trace_processor/importers/systrace/systrace_line.h"
diff --git a/src/trace_processor/sorter/trace_sorter_unittest.cc b/src/trace_processor/sorter/trace_sorter_unittest.cc
index 3fc8f76..42421df 100644
--- a/src/trace_processor/sorter/trace_sorter_unittest.cc
+++ b/src/trace_processor/sorter/trace_sorter_unittest.cc
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "perfetto/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/importers/proto/proto_trace_parser_impl.h"
+#include "src/trace_processor/sorter/trace_sorter.h"
 
 #include <map>
 #include <random>
@@ -22,9 +21,10 @@
 
 #include "perfetto/trace_processor/basic_types.h"
 #include "perfetto/trace_processor/trace_blob.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
 #include "src/trace_processor/importers/common/parser_types.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/sorter/trace_sorter.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/proto_trace_parser_impl.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 #include "test/gtest_and_gmock.h"
 
@@ -105,26 +105,25 @@
 };
 
 TEST_F(TraceSorterTest, TestFtrace) {
-  PacketSequenceState state(&context_);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
   TraceBlobView view = test_buffer_.slice_off(0, 1);
   EXPECT_CALL(*parser_,
               MOCK_ParseFtracePacket(0, 1000, view.data(), 1, kNullMachineId));
   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
-                                   std::move(view), state.current_generation());
+                                   std::move(view), state);
   context_.sorter->ExtractEventsForced();
 }
 
 TEST_F(TraceSorterTest, TestTracePacket) {
-  PacketSequenceState state(&context_);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
   TraceBlobView view = test_buffer_.slice_off(0, 1);
   EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1000, view.data(), 1));
-  context_.sorter->PushTracePacket(1000, state.current_generation(),
-                                   std::move(view));
+  context_.sorter->PushTracePacket(1000, state, std::move(view));
   context_.sorter->ExtractEventsForced();
 }
 
 TEST_F(TraceSorterTest, Ordering) {
-  PacketSequenceState state(&context_);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
   TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
   TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
   TraceBlobView view_3 = test_buffer_.slice_off(0, 3);
@@ -140,22 +139,18 @@
                                                kNullMachineId));
 
   context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
-                                   std::move(view_4),
-                                   state.current_generation());
-  context_.sorter->PushTracePacket(1001, state.current_generation(),
-                                   std::move(view_2));
-  context_.sorter->PushTracePacket(1100, state.current_generation(),
-                                   std::move(view_3));
+                                   std::move(view_4), state);
+  context_.sorter->PushTracePacket(1001, state, std::move(view_2));
+  context_.sorter->PushTracePacket(1100, state, std::move(view_3));
   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
-                                   std::move(view_1),
-                                   state.current_generation());
+                                   std::move(view_1), state);
   context_.sorter->ExtractEventsForced();
 }
 
 TEST_F(TraceSorterTest, IncrementalExtraction) {
   CreateSorter(false);
 
-  PacketSequenceState state(&context_);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
 
   TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
   TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
@@ -166,10 +161,8 @@
   // Flush at the start of packet sequence to match behavior of the
   // service.
   context_.sorter->NotifyFlushEvent();
-  context_.sorter->PushTracePacket(1200, state.current_generation(),
-                                   std::move(view_2));
-  context_.sorter->PushTracePacket(1100, state.current_generation(),
-                                   std::move(view_1));
+  context_.sorter->PushTracePacket(1200, state, std::move(view_2));
+  context_.sorter->PushTracePacket(1100, state, std::move(view_1));
 
   // No data should be exttracted at this point because we haven't
   // seen two flushes yet.
@@ -182,10 +175,8 @@
 
   context_.sorter->NotifyFlushEvent();
   context_.sorter->NotifyFlushEvent();
-  context_.sorter->PushTracePacket(1400, state.current_generation(),
-                                   std::move(view_4));
-  context_.sorter->PushTracePacket(1300, state.current_generation(),
-                                   std::move(view_3));
+  context_.sorter->PushTracePacket(1400, state, std::move(view_4));
+  context_.sorter->PushTracePacket(1300, state, std::move(view_3));
 
   // This ReadBuffer call should finally extract until the first OnReadBuffer
   // call.
@@ -197,8 +188,7 @@
   context_.sorter->NotifyReadBufferEvent();
 
   context_.sorter->NotifyFlushEvent();
-  context_.sorter->PushTracePacket(1500, state.current_generation(),
-                                   std::move(view_5));
+  context_.sorter->PushTracePacket(1500, state, std::move(view_5));
 
   // Nothing should be extracted as we haven't seen the second flush.
   context_.sorter->NotifyReadBufferEvent();
@@ -222,7 +212,7 @@
 TEST_F(TraceSorterTest, OutOfOrder) {
   CreateSorter(false);
 
-  PacketSequenceState state(&context_);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
 
   TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
   TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
@@ -231,10 +221,8 @@
 
   context_.sorter->NotifyFlushEvent();
   context_.sorter->NotifyFlushEvent();
-  context_.sorter->PushTracePacket(1200, state.current_generation(),
-                                   std::move(view_2));
-  context_.sorter->PushTracePacket(1100, state.current_generation(),
-                                   std::move(view_1));
+  context_.sorter->PushTracePacket(1200, state, std::move(view_2));
+  context_.sorter->PushTracePacket(1100, state, std::move(view_1));
   context_.sorter->NotifyReadBufferEvent();
 
   // Both of the packets should have been pushed through.
@@ -250,8 +238,7 @@
   // Now, pass the third packet out of order.
   context_.sorter->NotifyFlushEvent();
   context_.sorter->NotifyFlushEvent();
-  context_.sorter->PushTracePacket(1150, state.current_generation(),
-                                   std::move(view_3));
+  context_.sorter->PushTracePacket(1150, state, std::move(view_3));
   context_.sorter->NotifyReadBufferEvent();
 
   // The third packet should still be pushed through.
@@ -268,8 +255,7 @@
   // Push the fourth packet also out of order but after third.
   context_.sorter->NotifyFlushEvent();
   context_.sorter->NotifyFlushEvent();
-  context_.sorter->PushTracePacket(1170, state.current_generation(),
-                                   std::move(view_4));
+  context_.sorter->PushTracePacket(1170, state, std::move(view_4));
   context_.sorter->NotifyReadBufferEvent();
 
   // The fourt packet should still be pushed through.
@@ -286,7 +272,7 @@
 // Tests that the output of the TraceSorter matches the timestamp order
 // (% events happening at the same time on different CPUs).
 TEST_F(TraceSorterTest, MultiQueueSorting) {
-  PacketSequenceState state(&context_);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
   std::minstd_rand0 rnd_engine(0);
   std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;
 
@@ -320,8 +306,7 @@
     for (uint8_t j = 0; j < num_cpus; j++) {
       uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
       expectations[ts].push_back(cpu);
-      context_.sorter->PushFtraceEvent(cpu, ts, tbv.slice_off(i, 1),
-                                       state.current_generation());
+      context_.sorter->PushFtraceEvent(cpu, ts, tbv.slice_off(i, 1), state);
     }
   }
 
@@ -331,7 +316,7 @@
 
 // An generalized version of MultiQueueSorting with multiple machines.
 TEST_F(TraceSorterTest, MultiMachineSorting) {
-  PacketSequenceState state(&context_);
+  auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
   std::minstd_rand0 rnd_engine(0);
 
   struct ExpectedMachineAndCpu {
@@ -426,9 +411,8 @@
       for (uint8_t j = 0; j < num_cpus; j++) {
         uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
         expectations[ts].push_back(ExpectedMachineAndCpu{machine, cpu});
-        context_.sorter->PushFtraceEvent(cpu, ts,
-                                         tbv.slice_off(m * alloc_size + i, 1),
-                                         state.current_generation(), machine);
+        context_.sorter->PushFtraceEvent(
+            cpu, ts, tbv.slice_off(m * alloc_size + i, 1), state, machine);
       }
     }
   }
diff --git a/src/trace_processor/sorter/trace_token_buffer_unittest.cc b/src/trace_processor/sorter/trace_token_buffer_unittest.cc
index a8657d2..59f7e93 100644
--- a/src/trace_processor/sorter/trace_token_buffer_unittest.cc
+++ b/src/trace_processor/sorter/trace_token_buffer_unittest.cc
@@ -19,10 +19,11 @@
 #include <optional>
 
 #include "perfetto/base/compiler.h"
+#include "perfetto/trace_processor/ref_counted.h"
 #include "perfetto/trace_processor/trace_blob.h"
 #include "perfetto/trace_processor/trace_blob_view.h"
 #include "src/trace_processor/importers/common/parser_types.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 #include "test/gtest_and_gmock.h"
 
@@ -34,17 +35,18 @@
  protected:
   TraceTokenBuffer store;
   TraceProcessorContext context;
-  PacketSequenceState state{&context};
+  RefPtr<PacketSequenceStateGeneration> state =
+      PacketSequenceStateGeneration::CreateFirst(&context);
 };
 
 TEST_F(TraceTokenBufferUnittest, TracePacketDataInOut) {
   TraceBlobView tbv(TraceBlob::Allocate(1024));
-  TracePacketData tpd{tbv.copy(), state.current_generation()};
+  TracePacketData tpd{tbv.copy(), state};
 
   TraceTokenBuffer::Id id = store.Append(std::move(tpd));
   TracePacketData extracted = store.Extract<TracePacketData>(id);
   ASSERT_EQ(extracted.packet, tbv);
-  ASSERT_EQ(extracted.sequence_state, state.current_generation());
+  ASSERT_EQ(extracted.sequence_state, state);
 }
 
 TEST_F(TraceTokenBufferUnittest, PacketAppendMultipleBlobs) {
@@ -53,14 +55,14 @@
   TraceBlobView tbv_3(TraceBlob::Allocate(4096));
 
   TraceTokenBuffer::Id id_1 =
-      store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+      store.Append(TracePacketData{tbv_1.copy(), state});
   TraceTokenBuffer::Id id_2 =
-      store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
+      store.Append(TracePacketData{tbv_2.copy(), state});
   ASSERT_EQ(store.Extract<TracePacketData>(id_1).packet, tbv_1);
   ASSERT_EQ(store.Extract<TracePacketData>(id_2).packet, tbv_2);
 
   TraceTokenBuffer::Id id_3 =
-      store.Append(TracePacketData{tbv_3.copy(), state.current_generation()});
+      store.Append(TracePacketData{tbv_3.copy(), state});
   ASSERT_EQ(store.Extract<TracePacketData>(id_3).packet, tbv_3);
 }
 
@@ -71,14 +73,14 @@
   TraceBlobView tbv_3 = root.slice_off(1536, 512);
 
   TraceTokenBuffer::Id id_1 =
-      store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+      store.Append(TracePacketData{tbv_1.copy(), state});
   TraceTokenBuffer::Id id_2 =
-      store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
+      store.Append(TracePacketData{tbv_2.copy(), state});
   ASSERT_EQ(store.Extract<TracePacketData>(id_1).packet, tbv_1);
   ASSERT_EQ(store.Extract<TracePacketData>(id_2).packet, tbv_2);
 
   TraceTokenBuffer::Id id_3 =
-      store.Append(TracePacketData{tbv_3.copy(), state.current_generation()});
+      store.Append(TracePacketData{tbv_3.copy(), state});
   ASSERT_EQ(store.Extract<TracePacketData>(id_3).packet, tbv_3);
 }
 
@@ -88,13 +90,11 @@
   TraceBlobView tbv_2 = root.slice_off(1024, 512);
 
   TraceTokenBuffer::Id id_1 =
-      store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+      store.Append(TracePacketData{tbv_1.copy(), state});
   TraceTokenBuffer::Id id_2 =
-      store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
-  ASSERT_EQ(store.Extract<TracePacketData>(id_1).sequence_state,
-            state.current_generation());
-  ASSERT_EQ(store.Extract<TracePacketData>(id_2).sequence_state,
-            state.current_generation());
+      store.Append(TracePacketData{tbv_2.copy(), state});
+  ASSERT_EQ(store.Extract<TracePacketData>(id_1).sequence_state, state);
+  ASSERT_EQ(store.Extract<TracePacketData>(id_2).sequence_state, state);
 }
 
 TEST_F(TraceTokenBufferUnittest, ManySequenceState) {
@@ -103,10 +103,9 @@
   std::array<TraceTokenBuffer::Id, 1024> ids;
   std::array<PacketSequenceStateGeneration*, 1024> refs;
   for (uint32_t i = 0; i < 1024; ++i) {
-    refs[i] = state.current_generation().get();
-    ids[i] = store.Append(
-        TracePacketData{root.slice_off(i, 1), state.current_generation()});
-    state.OnIncrementalStateCleared();
+    refs[i] = state.get();
+    ids[i] = store.Append(TracePacketData{root.slice_off(i, 1), state});
+    state = state->OnNewTracePacketDefaults(TraceBlobView());
   }
 
   for (uint32_t i = 0; i < 1024; ++i) {
@@ -120,22 +119,22 @@
 
   TraceBlobView slice_1 = tbv.slice_off(0, 1024ul);
   TraceTokenBuffer::Id id_1 =
-      store.Append(TracePacketData{slice_1.copy(), state.current_generation()});
+      store.Append(TracePacketData{slice_1.copy(), state});
   TracePacketData out_1 = store.Extract<TracePacketData>(id_1);
   ASSERT_EQ(out_1.packet, slice_1);
-  ASSERT_EQ(out_1.sequence_state, state.current_generation());
+  ASSERT_EQ(out_1.sequence_state, state);
 
   TraceBlobView slice_2 = tbv.slice_off(128ul * 1024, 1024ul);
   TraceTokenBuffer::Id id_2 =
-      store.Append(TracePacketData{slice_2.copy(), state.current_generation()});
+      store.Append(TracePacketData{slice_2.copy(), state});
   TracePacketData out_2 = store.Extract<TracePacketData>(id_2);
   ASSERT_EQ(out_2.packet, slice_2);
-  ASSERT_EQ(out_2.sequence_state, state.current_generation());
+  ASSERT_EQ(out_2.sequence_state, state);
 }
 
 TEST_F(TraceTokenBufferUnittest, TrackEventDataInOut) {
   TraceBlobView tbv(TraceBlob::Allocate(1234));
-  TrackEventData ted(tbv.copy(), state.current_generation());
+  TrackEventData ted(tbv.copy(), state);
   ted.thread_instruction_count = 123;
   ted.extra_counter_values = {10, 2, 0, 0, 0, 0, 0, 0};
   auto counter_array = ted.extra_counter_values;
@@ -143,8 +142,7 @@
   TraceTokenBuffer::Id id = store.Append(std::move(ted));
   TrackEventData extracted = store.Extract<TrackEventData>(id);
   ASSERT_EQ(extracted.trace_packet_data.packet, tbv);
-  ASSERT_EQ(extracted.trace_packet_data.sequence_state,
-            state.current_generation());
+  ASSERT_EQ(extracted.trace_packet_data.sequence_state, state);
   ASSERT_EQ(extracted.thread_instruction_count, 123);
   ASSERT_EQ(extracted.thread_timestamp, std::nullopt);
   ASSERT_DOUBLE_EQ(extracted.counter_value, 0.0);
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index 13aefe5..9f341ab 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -291,6 +291,7 @@
     "../../protozero:testing_messages_zero",
     "../importers/proto:gen_cc_track_event_descriptor",
     "../importers/proto:minimal",
+    "../importers/proto:packet_sequence_state_generation_hdr",
     "../storage",
     "../types",
   ]
diff --git a/src/trace_processor/util/debug_annotation_parser_unittest.cc b/src/trace_processor/util/debug_annotation_parser_unittest.cc
index d9a4168..902e9da 100644
--- a/src/trace_processor/util/debug_annotation_parser_unittest.cc
+++ b/src/trace_processor/util/debug_annotation_parser_unittest.cc
@@ -18,6 +18,7 @@
 
 #include "perfetto/ext/base/string_view.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
+#include "perfetto/trace_processor/ref_counted.h"
 #include "perfetto/trace_processor/trace_blob.h"
 #include "perfetto/trace_processor/trace_blob_view.h"
 #include "protos/perfetto/common/descriptor.pbzero.h"
@@ -27,7 +28,8 @@
 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
 #include "protos/perfetto/trace/track_event/source_location.pbzero.h"
 #include "src/protozero/test/example_proto/test_messages.pbzero.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_builder.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/test_messages.descriptor.h"
 #include "src/trace_processor/types/trace_processor_context.h"
@@ -54,13 +56,13 @@
 class DebugAnnotationParserTest : public ::testing::Test,
                                   public ProtoToArgsParser::Delegate {
  protected:
-  DebugAnnotationParserTest() : sequence_state_(&context_) {
-    context_.storage.reset(new TraceStorage());
-  }
+  DebugAnnotationParserTest() { context_.storage.reset(new TraceStorage()); }
 
   const std::vector<std::string>& args() const { return args_; }
 
-  PacketSequenceState* mutable_seq_state() { return &sequence_state_; }
+  void InternMessage(uint32_t field_id, TraceBlobView message) {
+    state_builder_.InternMessage(field_id, std::move(message));
+  }
 
  private:
   using Key = ProtoToArgsParser::Key;
@@ -132,23 +134,19 @@
 
   InternedMessageView* GetInternedMessageView(uint32_t field_id,
                                               uint64_t iid) override {
-    if (field_id !=
-        protos::pbzero::InternedData::kDebugAnnotationStringValuesFieldNumber) {
-      return nullptr;
-    }
-    return sequence_state_.current_generation()->GetInternedMessageView(
-        field_id, iid);
+    return state_builder_.current_generation()->GetInternedMessageView(field_id,
+                                                                       iid);
   }
 
   PacketSequenceStateGeneration* seq_state() final {
-    return sequence_state_.current_generation().get();
+    return state_builder_.current_generation().get();
   }
 
   std::vector<std::string> args_;
   std::map<std::string, size_t> array_indices_;
 
   TraceProcessorContext context_;
-  PacketSequenceState sequence_state_;
+  PacketSequenceStateBuilder state_builder_{&context_};
 };
 
 // This test checks that in when an array is nested inside a dict which is
@@ -303,7 +301,7 @@
   string->set_str("foo");
   std::vector<uint8_t> data_serialized = string.SerializeAsArray();
 
-  mutable_seq_state()->InternMessage(
+  InternMessage(
       protos::pbzero::InternedData::kDebugAnnotationStringValuesFieldNumber,
       TraceBlobView(
           TraceBlob::CopyFrom(data_serialized.data(), data_serialized.size())));
diff --git a/src/trace_processor/util/interned_message_view.h b/src/trace_processor/util/interned_message_view.h
index f6a9a13..7ee28c3 100644
--- a/src/trace_processor/util/interned_message_view.h
+++ b/src/trace_processor/util/interned_message_view.h
@@ -103,7 +103,7 @@
     return submessage_view;
   }
 
-  const TraceBlobView& message() { return message_; }
+  const TraceBlobView& message() const { return message_; }
 
  private:
   using SubMessageViewMap =