tp: extract out track event methods from track tracker

This CL splits out all track event functionality from TrackTracker into
a new class called TrackEventTracker. This reduces the complexity of
TrackTracker significatly and removes some non-track related
functionality

Eventually, once we manage to refactor TrackEventTracker some more, we
will move all track creation back to TrackTracker.

There should be no functional changes in this CL.

Change-Id: I7ae223d2f4591e9e72c7ecc6a21ee3acf737beb2
diff --git a/Android.bp b/Android.bp
index 9516297..f124b24 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7410,6 +7410,7 @@
     "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_tokenizer.cc",
+    "src/trace_processor/importers/proto/track_event_tracker.cc",
     "src/trace_processor/trace_processor_context.cc",
     "src/trace_processor/trace_processor_storage.cc",
     "src/trace_processor/trace_processor_storage_impl.cc",
diff --git a/BUILD b/BUILD
index 8a1fa06..1c16af5 100644
--- a/BUILD
+++ b/BUILD
@@ -1228,6 +1228,8 @@
         "src/trace_processor/importers/proto/track_event_parser.h",
         "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",
+        "src/trace_processor/importers/proto/track_event_tracker.h",
         "src/trace_processor/importers/syscalls/syscall_tracker.h",
         "src/trace_processor/importers/systrace/systrace_line.h",
         "src/trace_processor/timestamped_trace_piece.h",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 234f159..b6b0ae8 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -123,6 +123,8 @@
     "importers/proto/track_event_parser.h",
     "importers/proto/track_event_tokenizer.cc",
     "importers/proto/track_event_tokenizer.h",
+    "importers/proto/track_event_tracker.cc",
+    "importers/proto/track_event_tracker.h",
     "importers/syscalls/syscall_tracker.h",
     "importers/systrace/systrace_line.h",
     "timestamped_trace_piece.h",
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index 12b2e2a..1dba4d2 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -31,6 +31,7 @@
 #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/types/trace_processor_context.h"
 
 #include "test/gtest_and_gmock.h"
@@ -739,14 +740,15 @@
       {kTimestamp, 0, track, cat_id, name_id, 0, 0, 0});
 
   // Global track.
-  TrackId track2 = context_.track_tracker->GetOrCreateDefaultDescriptorTrack();
+  TrackEventTracker track_event_tracker(&context_);
+  TrackId track2 = track_event_tracker.GetOrCreateDefaultDescriptorTrack();
   context_.args_tracker->Flush();  // Flush track args.
   context_.storage->mutable_slice_table()->Insert(
       {kTimestamp2, 0, track2, cat_id, name_id, 0, 0, 0});
 
   // Async event track.
-  context_.track_tracker->ReserveDescriptorChildTrack(1234, 0, kNullStringId);
-  TrackId track3 = *context_.track_tracker->GetDescriptorTrack(1234);
+  track_event_tracker.ReserveDescriptorChildTrack(1234, 0, kNullStringId);
+  TrackId track3 = *track_event_tracker.GetDescriptorTrack(1234);
   context_.args_tracker->Flush();  // Flush track args.
   context_.storage->mutable_slice_table()->Insert(
       {kTimestamp3, 0, track3, cat_id, name_id, 0, 0, 0});
diff --git a/src/trace_processor/importers/common/track_tracker.cc b/src/trace_processor/importers/common/track_tracker.cc
index bd1b390..98e97ef 100644
--- a/src/trace_processor/importers/common/track_tracker.cc
+++ b/src/trace_processor/importers/common/track_tracker.cc
@@ -22,9 +22,6 @@
 namespace perfetto {
 namespace trace_processor {
 
-// static
-constexpr uint64_t TrackTracker::kDefaultDescriptorTrackUuid;
-
 TrackTracker::TrackTracker(TraceProcessorContext* context)
     : source_key_(context->storage->InternString("source")),
       source_id_key_(context->storage->InternString("source_id")),
@@ -36,9 +33,6 @@
       fuchsia_source_(context->storage->InternString("fuchsia")),
       chrome_source_(context->storage->InternString("chrome")),
       android_source_(context->storage->InternString("android")),
-      descriptor_source_(context->storage->InternString("descriptor")),
-      default_descriptor_track_name_(
-          context->storage->InternString("Default Track")),
       context_(context) {}
 
 TrackId TrackTracker::InternThreadTrack(UniqueTid utid) {
@@ -176,382 +170,6 @@
   return *chrome_global_instant_track_id_;
 }
 
-void TrackTracker::ReserveDescriptorProcessTrack(uint64_t uuid,
-                                                 StringId name,
-                                                 uint32_t pid,
-                                                 int64_t timestamp) {
-  DescriptorTrackReservation reservation;
-  reservation.min_timestamp = timestamp;
-  reservation.pid = pid;
-  reservation.name = name;
-
-  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
-  bool inserted;
-  std::tie(it, inserted) =
-      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
-
-  if (inserted)
-    return;
-
-  if (!it->second.IsForSameTrack(reservation)) {
-    // Process tracks should not be reassigned to a different pid later (neither
-    // should the type of the track change).
-    PERFETTO_DLOG("New track reservation for process track with uuid %" PRIu64
-                  " doesn't match earlier one",
-                  uuid);
-    context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
-    return;
-  }
-
-  it->second.min_timestamp = std::min(it->second.min_timestamp, timestamp);
-}
-
-void TrackTracker::ReserveDescriptorThreadTrack(uint64_t uuid,
-                                                uint64_t parent_uuid,
-                                                StringId name,
-                                                uint32_t pid,
-                                                uint32_t tid,
-                                                int64_t timestamp) {
-  DescriptorTrackReservation reservation;
-  reservation.min_timestamp = timestamp;
-  reservation.parent_uuid = parent_uuid;
-  reservation.pid = pid;
-  reservation.tid = tid;
-  reservation.name = name;
-
-  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
-  bool inserted;
-  std::tie(it, inserted) =
-      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
-
-  if (inserted)
-    return;
-
-  if (!it->second.IsForSameTrack(reservation)) {
-    // Thread tracks should not be reassigned to a different pid/tid later
-    // (neither should the type of the track change).
-    PERFETTO_DLOG("New track reservation for thread track with uuid %" PRIu64
-                  " doesn't match earlier one",
-                  uuid);
-    context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
-    return;
-  }
-
-  it->second.min_timestamp = std::min(it->second.min_timestamp, timestamp);
-}
-
-void TrackTracker::ReserveDescriptorCounterTrack(uint64_t uuid,
-                                                 uint64_t parent_uuid,
-                                                 StringId name,
-                                                 StringId category,
-                                                 int64_t unit_multiplier,
-                                                 bool is_incremental,
-                                                 uint32_t packet_sequence_id) {
-  DescriptorTrackReservation reservation;
-  reservation.parent_uuid = parent_uuid;
-  reservation.is_counter = true;
-  reservation.name = name;
-  reservation.category = category;
-  reservation.unit_multiplier = unit_multiplier;
-  reservation.is_incremental = is_incremental;
-  // Incrementally encoded counters are only valid on a single sequence.
-  if (is_incremental)
-    reservation.packet_sequence_id = packet_sequence_id;
-
-  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
-  bool inserted;
-  std::tie(it, inserted) =
-      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
-
-  if (inserted || it->second.IsForSameTrack(reservation))
-    return;
-
-  // Counter tracks should not be reassigned to a different parent track later
-  // (neither should the type of the track change).
-  PERFETTO_DLOG("New track reservation for counter track with uuid %" PRIu64
-                " doesn't match earlier one",
-                uuid);
-  context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
-}
-
-void TrackTracker::ReserveDescriptorChildTrack(uint64_t uuid,
-                                               uint64_t parent_uuid,
-                                               StringId name) {
-  DescriptorTrackReservation reservation;
-  reservation.parent_uuid = parent_uuid;
-  reservation.name = name;
-
-  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
-  bool inserted;
-  std::tie(it, inserted) =
-      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
-
-  if (inserted || it->second.IsForSameTrack(reservation))
-    return;
-
-  // Child tracks should not be reassigned to a different parent track later
-  // (neither should the type of the track change).
-  PERFETTO_DLOG("New track reservation for child track with uuid %" PRIu64
-                " doesn't match earlier one",
-                uuid);
-  context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
-}
-
-base::Optional<TrackId> TrackTracker::GetDescriptorTrack(uint64_t uuid,
-                                                         StringId event_name) {
-  base::Optional<TrackId> track_id = GetDescriptorTrackImpl(uuid);
-  if (!track_id || event_name.is_null())
-    return track_id;
-
-  // Update the name of the track if unset and the track is not the primary
-  // track of a process/thread or a counter track.
-  auto* tracks = context_->storage->mutable_track_table();
-  uint32_t row = *tracks->id().IndexOf(*track_id);
-  if (!tracks->name()[row].is_null())
-    return track_id;
-
-  // Check reservation for track type.
-  auto reservation_it = reserved_descriptor_tracks_.find(uuid);
-  PERFETTO_CHECK(reservation_it != reserved_descriptor_tracks_.end());
-
-  if (reservation_it->second.pid || reservation_it->second.tid ||
-      reservation_it->second.is_counter) {
-    return track_id;
-  }
-  tracks->mutable_name()->Set(row, event_name);
-  return track_id;
-}
-
-base::Optional<TrackId> TrackTracker::GetDescriptorTrackImpl(
-    uint64_t uuid,
-    std::vector<uint64_t>* descendent_uuids) {
-  auto it = resolved_descriptor_tracks_.find(uuid);
-  if (it != resolved_descriptor_tracks_.end())
-    return it->second;
-
-  auto reservation_it = reserved_descriptor_tracks_.find(uuid);
-  if (reservation_it == reserved_descriptor_tracks_.end())
-    return base::nullopt;
-
-  TrackId track_id =
-      ResolveDescriptorTrack(uuid, reservation_it->second, descendent_uuids);
-  resolved_descriptor_tracks_[uuid] = track_id;
-  return track_id;
-}
-
-TrackId TrackTracker::ResolveDescriptorTrack(
-    uint64_t uuid,
-    const DescriptorTrackReservation& reservation,
-    std::vector<uint64_t>* descendent_uuids) {
-  auto set_track_name_and_return = [this, &reservation](TrackId track_id) {
-    if (reservation.name.is_null())
-      return track_id;
-
-    // Initialize the track name here, so that, if a name was given in the
-    // reservation, it is set immediately after resolution takes place.
-    auto* tracks = context_->storage->mutable_track_table();
-    tracks->mutable_name()->Set(*tracks->id().IndexOf(track_id),
-                                reservation.name);
-    return track_id;
-  };
-
-  static constexpr size_t kMaxAncestors = 10;
-
-  // Try to resolve any parent tracks recursively, too.
-  base::Optional<TrackId> parent_track_id;
-  if (reservation.parent_uuid) {
-    // Input data may contain loops or extremely long ancestor track chains. To
-    // avoid stack overflow in these situations, we keep track of the ancestors
-    // seen in the recursion.
-    std::unique_ptr<std::vector<uint64_t>> owned_descendent_uuids;
-    if (!descendent_uuids) {
-      owned_descendent_uuids.reset(new std::vector<uint64_t>());
-      descendent_uuids = owned_descendent_uuids.get();
-    }
-    descendent_uuids->push_back(uuid);
-
-    if (descendent_uuids->size() > kMaxAncestors) {
-      PERFETTO_ELOG(
-          "Too many ancestors in parent_track_uuid hierarchy at track %" PRIu64
-          " with parent %" PRIu64,
-          uuid, reservation.parent_uuid);
-    } else if (std::find(descendent_uuids->begin(), descendent_uuids->end(),
-                         reservation.parent_uuid) != descendent_uuids->end()) {
-      PERFETTO_ELOG(
-          "Loop detected in parent_track_uuid hierarchy at track %" PRIu64
-          " with parent %" PRIu64,
-          uuid, reservation.parent_uuid);
-    } else {
-      parent_track_id =
-          GetDescriptorTrackImpl(reservation.parent_uuid, descendent_uuids);
-      if (!parent_track_id) {
-        PERFETTO_ELOG("Unknown parent track %" PRIu64 " for track %" PRIu64,
-                      reservation.parent_uuid, uuid);
-      }
-    }
-
-    descendent_uuids->pop_back();
-    if (owned_descendent_uuids)
-      descendent_uuids = nullptr;
-  }
-
-  if (reservation.tid) {
-    UniqueTid utid = context_->process_tracker->UpdateThread(*reservation.tid,
-                                                             *reservation.pid);
-    auto it_and_inserted =
-        descriptor_uuids_by_utid_.insert(std::make_pair<>(utid, uuid));
-    if (!it_and_inserted.second) {
-      // We already saw a another track with a different uuid for this thread.
-      // Since there should only be one descriptor track for each thread, we
-      // assume that its tid was reused. So, start a new thread.
-      uint64_t old_uuid = it_and_inserted.first->second;
-      PERFETTO_DCHECK(old_uuid != uuid);  // Every track is only resolved once.
-
-      PERFETTO_DLOG("Detected tid reuse (pid: %" PRIu32 " tid: %" PRIu32
-                    ") from track descriptors (old uuid: %" PRIu64
-                    " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
-                    *reservation.pid, *reservation.tid, old_uuid, uuid,
-                    reservation.min_timestamp);
-
-      utid = context_->process_tracker->StartNewThread(base::nullopt,
-                                                       *reservation.tid);
-
-      // Associate the new thread with its process.
-      PERFETTO_CHECK(context_->process_tracker->UpdateThread(
-                         *reservation.tid, *reservation.pid) == utid);
-
-      descriptor_uuids_by_utid_[utid] = uuid;
-    }
-    return set_track_name_and_return(InternThreadTrack(utid));
-  }
-
-  if (reservation.pid) {
-    UniquePid upid =
-        context_->process_tracker->GetOrCreateProcess(*reservation.pid);
-    auto it_and_inserted =
-        descriptor_uuids_by_upid_.insert(std::make_pair<>(upid, uuid));
-    if (!it_and_inserted.second) {
-      // We already saw a another track with a different uuid for this process.
-      // Since there should only be one descriptor track for each process, we
-      // assume that its pid was reused. So, start a new process.
-      uint64_t old_uuid = it_and_inserted.first->second;
-      PERFETTO_DCHECK(old_uuid != uuid);  // Every track is only resolved once.
-
-      PERFETTO_DLOG("Detected pid reuse (pid: %" PRIu32
-                    ") from track descriptors (old uuid: %" PRIu64
-                    " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
-                    *reservation.pid, old_uuid, uuid,
-                    reservation.min_timestamp);
-
-      upid = context_->process_tracker->StartNewProcess(
-          base::nullopt, base::nullopt, *reservation.pid, kNullStringId);
-
-      descriptor_uuids_by_upid_[upid] = uuid;
-    }
-    return set_track_name_and_return(InternProcessTrack(upid));
-  }
-
-  base::Optional<TrackId> track_id;
-  if (parent_track_id) {
-    // If parent is a thread track, create another thread-associated track.
-    auto* thread_tracks = context_->storage->mutable_thread_track_table();
-    base::Optional<uint32_t> thread_track_index =
-        thread_tracks->id().IndexOf(*parent_track_id);
-    if (thread_track_index) {
-      if (reservation.is_counter) {
-        // Thread counter track.
-        auto* thread_counter_tracks =
-            context_->storage->mutable_thread_counter_track_table();
-        tables::ThreadCounterTrackTable::Row row;
-        row.utid = thread_tracks->utid()[*thread_track_index];
-        track_id = thread_counter_tracks->Insert(row).id;
-      } else {
-        // Thread slice track.
-        tables::ThreadTrackTable::Row row;
-        row.utid = thread_tracks->utid()[*thread_track_index];
-        track_id = thread_tracks->Insert(row).id;
-      }
-    } else {
-      // If parent is a process track, create another process-associated track.
-      auto* process_tracks = context_->storage->mutable_process_track_table();
-      base::Optional<uint32_t> process_track_index =
-          process_tracks->id().IndexOf(*parent_track_id);
-      if (process_track_index) {
-        if (reservation.is_counter) {
-          // Process counter track.
-          auto* process_counter_tracks =
-              context_->storage->mutable_process_counter_track_table();
-          tables::ProcessCounterTrackTable::Row row;
-          row.upid = process_tracks->upid()[*process_track_index];
-          track_id = process_counter_tracks->Insert(row).id;
-        } else {
-          // Process slice track.
-          tables::ProcessTrackTable::Row row;
-          row.upid = process_tracks->upid()[*process_track_index];
-          track_id = process_tracks->Insert(row).id;
-        }
-      }
-    }
-  }
-
-  // Otherwise create a global track.
-  if (!track_id) {
-    if (reservation.is_counter) {
-      // Global counter track.
-      tables::CounterTrackTable::Row row;
-      track_id =
-          context_->storage->mutable_counter_track_table()->Insert(row).id;
-    } else {
-      // Global slice track.
-      tables::TrackTable::Row row;
-      track_id = context_->storage->mutable_track_table()->Insert(row).id;
-    }
-    // The global track with no uuid is the default global track (e.g. for
-    // global instant events). Any other global tracks are considered children
-    // of the default track.
-    if (!parent_track_id && uuid) {
-      // Detect loops where the default track has a parent that itself is a
-      // global track (and thus should be parent of the default track).
-      if (descendent_uuids &&
-          std::find(descendent_uuids->begin(), descendent_uuids->end(),
-                    kDefaultDescriptorTrackUuid) != descendent_uuids->end()) {
-        PERFETTO_ELOG(
-            "Loop detected in parent_track_uuid hierarchy at track %" PRIu64
-            " with parent %" PRIu64,
-            uuid, kDefaultDescriptorTrackUuid);
-      } else {
-        parent_track_id = GetOrCreateDefaultDescriptorTrack();
-      }
-    }
-  }
-
-  auto args = context_->args_tracker->AddArgsTo(*track_id);
-  args.AddArg(source_key_, Variadic::String(descriptor_source_))
-      .AddArg(source_id_key_, Variadic::Integer(static_cast<int64_t>(uuid)));
-  if (parent_track_id) {
-    args.AddArg(parent_track_id_key_,
-                Variadic::Integer(parent_track_id->value));
-  }
-  if (reservation.category != kNullStringId) {
-    args.AddArg(category_key_, Variadic::String(reservation.category));
-  }
-  return set_track_name_and_return(*track_id);
-}
-
-TrackId TrackTracker::GetOrCreateDefaultDescriptorTrack() {
-  // If the default track was already reserved (e.g. because a producer emitted
-  // a descriptor for it) or created, resolve and return it.
-  base::Optional<TrackId> track_id =
-      GetDescriptorTrack(kDefaultDescriptorTrackUuid);
-  if (track_id)
-    return *track_id;
-
-  // Otherwise reserve a new track and resolve it.
-  ReserveDescriptorChildTrack(kDefaultDescriptorTrackUuid, /*parent_uuid=*/0,
-                              default_descriptor_track_name_);
-  return *GetDescriptorTrack(kDefaultDescriptorTrackUuid);
-}
-
 TrackId TrackTracker::GetOrCreateTriggerTrack() {
   if (trigger_track_id_) {
     return *trigger_track_id_;
@@ -682,61 +300,5 @@
   return context_->storage->mutable_gpu_counter_track_table()->Insert(row).id;
 }
 
-base::Optional<int64_t> TrackTracker::ConvertToAbsoluteCounterValue(
-    uint64_t counter_track_uuid,
-    uint32_t packet_sequence_id,
-    int64_t value) {
-  auto reservation_it = reserved_descriptor_tracks_.find(counter_track_uuid);
-  if (reservation_it == reserved_descriptor_tracks_.end()) {
-    PERFETTO_DLOG("Unknown counter track with uuid %" PRIu64,
-                  counter_track_uuid);
-    return base::nullopt;
-  }
-
-  DescriptorTrackReservation& reservation = reservation_it->second;
-  if (!reservation.is_counter) {
-    PERFETTO_DLOG("Track with uuid %" PRIu64 " is not a counter track",
-                  counter_track_uuid);
-    return base::nullopt;
-  }
-
-  if (reservation.unit_multiplier > 0)
-    value *= reservation.unit_multiplier;
-
-  if (reservation.is_incremental) {
-    if (reservation.packet_sequence_id != packet_sequence_id) {
-      PERFETTO_DLOG(
-          "Incremental counter track with uuid %" PRIu64
-          " was updated from the wrong packet sequence (expected: %" PRIu32
-          " got:%" PRIu32 ")",
-          counter_track_uuid, reservation.packet_sequence_id,
-          packet_sequence_id);
-      return base::nullopt;
-    }
-
-    reservation.latest_value += value;
-    value = reservation.latest_value;
-  }
-
-  return value;
-}
-
-void TrackTracker::OnIncrementalStateCleared(uint32_t packet_sequence_id) {
-  // TODO(eseckler): Improve on the runtime complexity of this. At O(hundreds)
-  // of packet sequences, incremental state clearing at O(trace second), and
-  // total number of tracks in O(thousands), a linear scan through all tracks
-  // here might not be fast enough.
-  for (auto& entry : reserved_descriptor_tracks_) {
-    DescriptorTrackReservation& reservation = entry.second;
-    // Only consider incremental counter tracks for current sequence.
-    if (!reservation.is_counter || !reservation.is_incremental ||
-        reservation.packet_sequence_id != packet_sequence_id) {
-      continue;
-    }
-    // Reset their value to 0, see CounterDescriptor's |is_incremental|.
-    reservation.latest_value = 0;
-  }
-}
-
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/common/track_tracker.h b/src/trace_processor/importers/common/track_tracker.h
index 0173e83..c4af0da 100644
--- a/src/trace_processor/importers/common/track_tracker.h
+++ b/src/trace_processor/importers/common/track_tracker.h
@@ -62,85 +62,6 @@
   // Lazily creates the track for legacy Chrome global instant events.
   TrackId GetOrCreateLegacyChromeGlobalInstantTrack();
 
-  // Associate a TrackDescriptor track identified by the given |uuid| with a
-  // process's |pid|. This is called during tokenization. If a reservation for
-  // the same |uuid| already exists, verifies that the present reservation
-  // matches the new one.
-  //
-  // The track will be resolved to the process track (see InternProcessTrack())
-  // upon the first call to GetDescriptorTrack() with the same |uuid|. At this
-  // time, |pid| will also be resolved to a |upid|.
-  void ReserveDescriptorProcessTrack(uint64_t uuid,
-                                     StringId name,
-                                     uint32_t pid,
-                                     int64_t timestamp);
-
-  // Associate a TrackDescriptor track identified by the given |uuid| with a
-  // thread's |pid| and |tid|. This is called during tokenization. If a
-  // reservation for the same |uuid| already exists, verifies that the present
-  // reservation matches the new one.
-  //
-  // The track will be resolved to the thread track (see InternThreadTrack())
-  // upon the first call to GetDescriptorTrack() with the same |uuid|. At this
-  // time, |pid| will also be resolved to a |upid|.
-  void ReserveDescriptorThreadTrack(uint64_t uuid,
-                                    uint64_t parent_uuid,
-                                    StringId name,
-                                    uint32_t pid,
-                                    uint32_t tid,
-                                    int64_t timestamp);
-
-  // Associate a TrackDescriptor track identified by the given |uuid| with a
-  // parent track (usually a process- or thread-associated track). This is
-  // called during tokenization. If a reservation for the same |uuid| already
-  // exists, will attempt to update it.
-  //
-  // The track will be created upon the first call to GetDescriptorTrack() with
-  // the same |uuid|. If |parent_uuid| is 0, the track will become a global
-  // track. Otherwise, it will become a new track of the same type as its parent
-  // track.
-  void ReserveDescriptorChildTrack(uint64_t uuid,
-                                   uint64_t parent_uuid,
-                                   StringId name);
-
-  // Associate a counter-type TrackDescriptor track identified by the given
-  // |uuid| with a parent track (usually a process or thread track). This is
-  // called during tokenization. If a reservation for the same |uuid| already
-  // exists, will attempt to update it. The provided |category| will be stored
-  // into the track's args.
-  //
-  // If |is_incremental| is true, the counter will only be valid on the packet
-  // sequence identified by |packet_sequence_id|. |unit_multiplier| is an
-  // optional multiplication factor applied to counter values. Values for the
-  // counter will be translated during tokenization via
-  // ConvertToAbsoluteCounterValue().
-  //
-  // The track will be created upon the first call to GetDescriptorTrack() with
-  // the same |uuid|. If |parent_uuid| is 0, the track will become a global
-  // track. Otherwise, it will become a new counter track for the same
-  // process/thread as its parent track.
-  void ReserveDescriptorCounterTrack(uint64_t uuid,
-                                     uint64_t parent_uuid,
-                                     StringId name,
-                                     StringId category,
-                                     int64_t unit_multiplier,
-                                     bool is_incremental,
-                                     uint32_t packet_sequence_id);
-
-  // Returns the ID of the track for the TrackDescriptor with the given |uuid|.
-  // This is called during parsing. The first call to GetDescriptorTrack() for
-  // each |uuid| resolves and inserts the track (and its parent tracks,
-  // following the parent_uuid chain recursively) based on reservations made for
-  // the |uuid|. If the track is a child track and doesn't have a name yet,
-  // updates the track's name to event_name. Returns nullopt if no track for a
-  // descriptor with this |uuid| has been reserved.
-  base::Optional<TrackId> GetDescriptorTrack(
-      uint64_t uuid,
-      StringId event_name = kNullStringId);
-
-  // Returns the ID of the implicit trace-global default TrackDescriptor track.
-  TrackId GetOrCreateDefaultDescriptorTrack();
-
   // Returns the ID of the implicit trace-global default track for triggers
   // received by the service.
   TrackId GetOrCreateTriggerTrack();
@@ -177,21 +98,6 @@
                                 StringId description = StringId::Null(),
                                 StringId unit = StringId::Null());
 
-  // Converts the given counter value to an absolute value in the unit of the
-  // counter, applying incremental delta encoding or unit multipliers as
-  // necessary. If the counter uses incremental encoding, |packet_sequence_id|
-  // must match the one in its track reservation. Returns base::nullopt if the
-  // counter track is unknown or an invalid |packet_sequence_id| was passed.
-  base::Optional<int64_t> ConvertToAbsoluteCounterValue(
-      uint64_t counter_track_uuid,
-      uint32_t packet_sequence_id,
-      int64_t value);
-
-  // Called by ProtoTraceReader whenever incremental state is cleared on a
-  // packet sequence. Resets counter values for any incremental counters of
-  // the sequence identified by |packet_sequence_id|.
-  void OnIncrementalStateCleared(uint32_t packet_sequence_id);
-
  private:
   struct GpuTrackTuple {
     StringId track_name;
@@ -214,41 +120,6 @@
              std::tie(r.source_id, r.upid, r.source_scope);
     }
   };
-  struct DescriptorTrackReservation {
-    uint64_t parent_uuid = 0;
-    base::Optional<uint32_t> pid;
-    base::Optional<uint32_t> tid;
-    int64_t min_timestamp = 0;  // only set if |pid| and/or |tid| is set.
-    StringId name = kNullStringId;
-
-    // For counter tracks.
-    bool is_counter = false;
-    StringId category = kNullStringId;
-    int64_t unit_multiplier = 1;
-    bool is_incremental = false;
-    uint32_t packet_sequence_id = 0;
-    int64_t latest_value = 0;
-
-    // Whether |other| is a valid descriptor for this track reservation. A track
-    // should always remain nested underneath its original parent.
-    bool IsForSameTrack(const DescriptorTrackReservation& other) {
-      // Note that |min_timestamp|, |latest_value|, and |name| are ignored for
-      // this comparison.
-      return std::tie(parent_uuid, pid, tid, is_counter, category,
-                      unit_multiplier, is_incremental, packet_sequence_id) ==
-             std::tie(other.parent_uuid, pid, tid, is_counter, category,
-                      unit_multiplier, is_incremental, packet_sequence_id);
-    }
-  };
-
-  base::Optional<TrackId> GetDescriptorTrackImpl(
-      uint64_t uuid,
-      std::vector<uint64_t>* descendent_uuids = nullptr);
-  TrackId ResolveDescriptorTrack(uint64_t uuid,
-                                 const DescriptorTrackReservation&,
-                                 std::vector<uint64_t>* descendent_uuids);
-
-  static constexpr uint64_t kDefaultDescriptorTrackUuid = 0u;
 
   std::map<UniqueTid, TrackId> thread_tracks_;
   std::map<UniquePid, TrackId> process_tracks_;
@@ -259,10 +130,6 @@
   std::map<GpuTrackTuple, TrackId> gpu_tracks_;
   std::map<ChromeTrackTuple, TrackId> chrome_tracks_;
   std::map<UniquePid, TrackId> chrome_process_instant_tracks_;
-  base::Optional<TrackId> chrome_global_instant_track_id_;
-  std::map<uint64_t /* uuid */, DescriptorTrackReservation>
-      reserved_descriptor_tracks_;
-  std::map<uint64_t /* uuid */, TrackId> resolved_descriptor_tracks_;
   std::map<UniquePid, TrackId> perf_stack_tracks_;
 
   std::map<StringId, TrackId> global_counter_tracks_by_name_;
@@ -273,11 +140,7 @@
   std::map<std::pair<StringId, int32_t>, TrackId> softirq_counter_tracks_;
   std::map<std::pair<StringId, uint32_t>, TrackId> gpu_counter_tracks_;
 
-  // Stores the descriptor uuid used for the primary process/thread track
-  // for the given upid / utid. Used for pid/tid reuse detection.
-  std::map<UniquePid, uint64_t /*uuid*/> descriptor_uuids_by_upid_;
-  std::map<UniqueTid, uint64_t /*uuid*/> descriptor_uuids_by_utid_;
-
+  base::Optional<TrackId> chrome_global_instant_track_id_;
   base::Optional<TrackId> trigger_track_id_;
 
   const StringId source_key_ = kNullStringId;
@@ -290,9 +153,6 @@
   const StringId fuchsia_source_ = kNullStringId;
   const StringId chrome_source_ = kNullStringId;
   const StringId android_source_ = kNullStringId;
-  const StringId descriptor_source_ = kNullStringId;
-
-  const StringId default_descriptor_track_name_ = kNullStringId;
 
   TraceProcessorContext* const context_;
 };
diff --git a/src/trace_processor/importers/proto/proto_importer_module.h b/src/trace_processor/importers/proto/proto_importer_module.h
index 74cc958..dda2f85 100644
--- a/src/trace_processor/importers/proto/proto_importer_module.h
+++ b/src/trace_processor/importers/proto/proto_importer_module.h
@@ -110,6 +110,13 @@
       PacketSequenceState*,
       uint32_t field_id);
 
+  // Called by ProtoTraceReader during the tokenization stage i.e. before
+  // sorting. Indicates that sequence with id |packet_sequence_id| has cleared
+  // its incremental state. This should be used to clear any cached state the
+  // tokenizer has built up while reading packets until this point for this
+  // packet sequence.
+  virtual void OnIncrementalStateCleared(uint32_t /* packet_sequence_id */) {}
+
   // Called by ProtoTraceParser after the sorting stage for each non-ftrace
   // TracePacket that contains fields for which the module was registered.
   virtual void ParsePacket(const protos::pbzero::TracePacket_Decoder&,
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index 5e12987..e2b1cde 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -258,8 +258,10 @@
   GetIncrementalStateForPacketSequence(
       packet_decoder.trusted_packet_sequence_id())
       ->OnIncrementalStateCleared();
-  context_->track_tracker->OnIncrementalStateCleared(
-      packet_decoder.trusted_packet_sequence_id());
+  for (auto& module : context_->modules) {
+    module->OnIncrementalStateCleared(
+        packet_decoder.trusted_packet_sequence_id());
+  }
 }
 
 void ProtoTraceReader::HandlePreviousPacketDropped(
diff --git a/src/trace_processor/importers/proto/track_event_module.cc b/src/trace_processor/importers/proto/track_event_module.cc
index a2fcf28..eb9d536 100644
--- a/src/trace_processor/importers/proto/track_event_module.cc
+++ b/src/trace_processor/importers/proto/track_event_module.cc
@@ -18,6 +18,7 @@
 #include "perfetto/base/build_config.h"
 #include "perfetto/ext/base/string_utils.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/importers/proto/track_event_tracker.h"
 #include "src/trace_processor/timestamped_trace_piece.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 
@@ -31,7 +32,9 @@
 using perfetto::protos::pbzero::TracePacket;
 
 TrackEventModule::TrackEventModule(TraceProcessorContext* context)
-    : tokenizer_(context), parser_(context) {
+    : track_event_tracker_(new TrackEventTracker(context)),
+      tokenizer_(context, track_event_tracker_.get()),
+      parser_(context, track_event_tracker_.get()) {
   RegisterForField(TracePacket::kTrackEventFieldNumber, context);
   RegisterForField(TracePacket::kTrackDescriptorFieldNumber, context);
   RegisterForField(TracePacket::kThreadDescriptorFieldNumber, context);
@@ -87,5 +90,9 @@
   }
 }
 
+void TrackEventModule::OnIncrementalStateCleared(uint32_t packet_sequence_id) {
+  track_event_tracker_->OnIncrementalStateCleared(packet_sequence_id);
+}
+
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/track_event_module.h b/src/trace_processor/importers/proto/track_event_module.h
index de31d47..0632747 100644
--- a/src/trace_processor/importers/proto/track_event_module.h
+++ b/src/trace_processor/importers/proto/track_event_module.h
@@ -39,11 +39,14 @@
       PacketSequenceState* state,
       uint32_t field_id) override;
 
+  void OnIncrementalStateCleared(uint32_t) override;
+
   void ParsePacket(const protos::pbzero::TracePacket::Decoder& decoder,
                    const TimestampedTracePiece& ttp,
                    uint32_t field_id) override;
 
  private:
+  std::unique_ptr<TrackEventTracker> track_event_tracker_;
   TrackEventTokenizer tokenizer_;
   TrackEventParser parser_;
 };
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 54db072..019d878 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/proto/args_table_utils.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
 #include "src/trace_processor/importers/proto/track_event.descriptor.h"
+#include "src/trace_processor/importers/proto/track_event_tracker.h"
 #include "src/trace_processor/util/status_macros.h"
 
 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
@@ -118,6 +119,7 @@
                 TrackEventData* event_data,
                 ConstBytes blob)
       : context_(parser->context_),
+        track_event_tracker_(parser->track_event_tracker_),
         storage_(context_->storage.get()),
         parser_(parser),
         ts_(ts),
@@ -286,11 +288,13 @@
     //   b) a default track.
     if (track_uuid_) {
       base::Optional<TrackId> opt_track_id =
-          track_tracker->GetDescriptorTrack(track_uuid_, name_id_);
+          track_event_tracker_->GetDescriptorTrack(track_uuid_, name_id_);
       if (!opt_track_id) {
-        track_tracker->ReserveDescriptorChildTrack(track_uuid_,
-                                                   /*parent_uuid=*/0, name_id_);
-        opt_track_id = track_tracker->GetDescriptorTrack(track_uuid_, name_id_);
+        track_event_tracker_->ReserveDescriptorChildTrack(track_uuid_,
+                                                          /*parent_uuid=*/0,
+                                                          name_id_);
+        opt_track_id =
+            track_event_tracker_->GetDescriptorTrack(track_uuid_, name_id_);
       }
       track_id_ = *opt_track_id;
 
@@ -364,7 +368,7 @@
         upid_ = storage_->thread_table().upid()[*utid_];
         track_id_ = track_tracker->InternThreadTrack(*utid_);
       } else {
-        track_id_ = track_tracker->GetOrCreateDefaultDescriptorTrack();
+        track_id_ = track_event_tracker_->GetOrCreateDefaultDescriptorTrack();
       }
     }
 
@@ -525,7 +529,7 @@
       PERFETTO_DCHECK(index < TrackEventData::kMaxNumExtraCounters);
 
       base::Optional<TrackId> track_id =
-          context_->track_tracker->GetDescriptorTrack(*track_uuid_it);
+          track_event_tracker_->GetDescriptorTrack(*track_uuid_it);
       base::Optional<uint32_t> counter_row =
           storage_->counter_track_table().id().IndexOf(*track_id);
 
@@ -1159,6 +1163,7 @@
   }
 
   TraceProcessorContext* context_;
+  TrackEventTracker* track_event_tracker_;
   TraceStorage* storage_;
   TrackEventParser* parser_;
   int64_t ts_;
@@ -1183,8 +1188,10 @@
   base::Optional<UniqueTid> legacy_passthrough_utid_;
 };
 
-TrackEventParser::TrackEventParser(TraceProcessorContext* context)
+TrackEventParser::TrackEventParser(TraceProcessorContext* context,
+                                   TrackEventTracker* track_event_tracker)
     : context_(context),
+      track_event_tracker_(track_event_tracker),
       counter_name_thread_time_id_(
           context->storage->InternString("thread_time")),
       counter_name_thread_instruction_count_id_(
@@ -1353,8 +1360,7 @@
 
   // Ensure that the track and its parents are resolved. This may start a new
   // process and/or thread (i.e. new upid/utid).
-  TrackId track_id =
-      *context_->track_tracker->GetDescriptorTrack(decoder.uuid());
+  TrackId track_id = *track_event_tracker_->GetDescriptorTrack(decoder.uuid());
 
   if (decoder.has_thread()) {
     UniqueTid utid = ParseThreadDescriptor(decoder.thread());
diff --git a/src/trace_processor/importers/proto/track_event_parser.h b/src/trace_processor/importers/proto/track_event_parser.h
index bd43784e..0f8d2a8 100644
--- a/src/trace_processor/importers/proto/track_event_parser.h
+++ b/src/trace_processor/importers/proto/track_event_parser.h
@@ -32,7 +32,6 @@
 }
 
 namespace perfetto {
-
 namespace trace_processor {
 
 // Field numbers to be added to args table automatically via reflection
@@ -45,10 +44,11 @@
 
 class PacketSequenceStateGeneration;
 class TraceProcessorContext;
+class TrackEventTracker;
 
 class TrackEventParser {
  public:
-  explicit TrackEventParser(TraceProcessorContext* context);
+  TrackEventParser(TraceProcessorContext*, TrackEventTracker*);
 
   void ParseTrackDescriptor(protozero::ConstBytes);
   UniquePid ParseProcessDescriptor(protozero::ConstBytes);
@@ -66,6 +66,7 @@
   void ParseCounterDescriptor(TrackId, protozero::ConstBytes);
 
   TraceProcessorContext* context_;
+  TrackEventTracker* track_event_tracker_;
 
   const StringId counter_name_thread_time_id_;
   const StringId counter_name_thread_instruction_count_id_;
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index 11df60b..42e663a 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -22,6 +22,7 @@
 #include "src/trace_processor/importers/common/track_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"
 #include "src/trace_processor/storage/stats.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/trace_blob_view.h"
@@ -44,8 +45,10 @@
 using protos::pbzero::CounterDescriptor;
 }
 
-TrackEventTokenizer::TrackEventTokenizer(TraceProcessorContext* context)
+TrackEventTokenizer::TrackEventTokenizer(TraceProcessorContext* context,
+                                         TrackEventTracker* track_event_tracker)
     : context_(context),
+      track_event_tracker_(track_event_tracker),
       counter_name_thread_time_id_(
           context_->storage->InternString("thread_time")),
       counter_name_thread_instruction_count_id_(
@@ -84,7 +87,7 @@
       TokenizeThreadDescriptor(state, thread);
     }
 
-    context_->track_tracker->ReserveDescriptorThreadTrack(
+    track_event_tracker_->ReserveDescriptorThreadTrack(
         track.uuid(), track.parent_uuid(), name_id,
         static_cast<uint32_t>(thread.pid()),
         static_cast<uint32_t>(thread.tid()), packet_timestamp);
@@ -98,7 +101,7 @@
       return ModuleResult::Handled();
     }
 
-    context_->track_tracker->ReserveDescriptorProcessTrack(
+    track_event_tracker_->ReserveDescriptorProcessTrack(
         track.uuid(), name_id, static_cast<uint32_t>(process.pid()),
         packet_timestamp);
   } else if (track.has_counter()) {
@@ -138,12 +141,12 @@
       }
     }
 
-    context_->track_tracker->ReserveDescriptorCounterTrack(
+    track_event_tracker_->ReserveDescriptorCounterTrack(
         track.uuid(), track.parent_uuid(), name_id, category_id,
         counter.unit_multiplier(), counter.is_incremental(),
         packet.trusted_packet_sequence_id());
   } else {
-    context_->track_tracker->ReserveDescriptorChildTrack(
+    track_event_tracker_->ReserveDescriptorChildTrack(
         track.uuid(), track.parent_uuid(), name_id);
   }
 
@@ -302,7 +305,7 @@
     }
 
     base::Optional<int64_t> value =
-        context_->track_tracker->ConvertToAbsoluteCounterValue(
+        track_event_tracker_->ConvertToAbsoluteCounterValue(
             track_uuid, packet.trusted_packet_sequence_id(),
             event.counter_value());
 
@@ -350,7 +353,7 @@
         return;
       }
       base::Optional<int64_t> value =
-          context_->track_tracker->ConvertToAbsoluteCounterValue(
+          track_event_tracker_->ConvertToAbsoluteCounterValue(
               *track_uuid_it, packet.trusted_packet_sequence_id(), *value_it);
       if (!value) {
         PERFETTO_DLOG("Ignoring TrackEvent with invalid extra counter track");
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.h b/src/trace_processor/importers/proto/track_event_tokenizer.h
index 6657a48..0595a59 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.h
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.h
@@ -38,10 +38,11 @@
 class PacketSequenceState;
 class TraceProcessorContext;
 class TraceBlobView;
+class TrackEventTracker;
 
 class TrackEventTokenizer {
  public:
-  explicit TrackEventTokenizer(TraceProcessorContext* context);
+  explicit TrackEventTokenizer(TraceProcessorContext*, TrackEventTracker*);
 
   ModuleResult TokenizeTrackDescriptorPacket(
       PacketSequenceState* state,
@@ -61,6 +62,7 @@
       const protos::pbzero::ThreadDescriptor_Decoder&);
 
   TraceProcessorContext* context_;
+  TrackEventTracker* track_event_tracker_;
 
   const StringId counter_name_thread_time_id_;
   const StringId counter_name_thread_instruction_count_id_;
diff --git a/src/trace_processor/importers/proto/track_event_tracker.cc b/src/trace_processor/importers/proto/track_event_tracker.cc
new file mode 100644
index 0000000..60195a3
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_tracker.cc
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2020 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_tracker.h"
+
+#include "src/trace_processor/importers/common/args_tracker.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/importers/common/track_tracker.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// static
+constexpr uint64_t TrackEventTracker::kDefaultDescriptorTrackUuid;
+
+TrackEventTracker::TrackEventTracker(TraceProcessorContext* context)
+    : source_key_(context->storage->InternString("source")),
+      source_id_key_(context->storage->InternString("source_id")),
+      parent_track_id_key_(context->storage->InternString("parent_track_id")),
+      category_key_(context->storage->InternString("category")),
+      descriptor_source_(context->storage->InternString("descriptor")),
+      default_descriptor_track_name_(
+          context->storage->InternString("Default Track")),
+      context_(context) {}
+
+void TrackEventTracker::ReserveDescriptorProcessTrack(uint64_t uuid,
+                                                      StringId name,
+                                                      uint32_t pid,
+                                                      int64_t timestamp) {
+  DescriptorTrackReservation reservation;
+  reservation.min_timestamp = timestamp;
+  reservation.pid = pid;
+  reservation.name = name;
+
+  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
+  bool inserted;
+  std::tie(it, inserted) =
+      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
+
+  if (inserted)
+    return;
+
+  if (!it->second.IsForSameTrack(reservation)) {
+    // Process tracks should not be reassigned to a different pid later (neither
+    // should the type of the track change).
+    PERFETTO_DLOG("New track reservation for process track with uuid %" PRIu64
+                  " doesn't match earlier one",
+                  uuid);
+    context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+    return;
+  }
+
+  it->second.min_timestamp = std::min(it->second.min_timestamp, timestamp);
+}
+
+void TrackEventTracker::ReserveDescriptorThreadTrack(uint64_t uuid,
+                                                     uint64_t parent_uuid,
+                                                     StringId name,
+                                                     uint32_t pid,
+                                                     uint32_t tid,
+                                                     int64_t timestamp) {
+  DescriptorTrackReservation reservation;
+  reservation.min_timestamp = timestamp;
+  reservation.parent_uuid = parent_uuid;
+  reservation.pid = pid;
+  reservation.tid = tid;
+  reservation.name = name;
+
+  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
+  bool inserted;
+  std::tie(it, inserted) =
+      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
+
+  if (inserted)
+    return;
+
+  if (!it->second.IsForSameTrack(reservation)) {
+    // Thread tracks should not be reassigned to a different pid/tid later
+    // (neither should the type of the track change).
+    PERFETTO_DLOG("New track reservation for thread track with uuid %" PRIu64
+                  " doesn't match earlier one",
+                  uuid);
+    context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+    return;
+  }
+
+  it->second.min_timestamp = std::min(it->second.min_timestamp, timestamp);
+}
+
+void TrackEventTracker::ReserveDescriptorCounterTrack(
+    uint64_t uuid,
+    uint64_t parent_uuid,
+    StringId name,
+    StringId category,
+    int64_t unit_multiplier,
+    bool is_incremental,
+    uint32_t packet_sequence_id) {
+  DescriptorTrackReservation reservation;
+  reservation.parent_uuid = parent_uuid;
+  reservation.is_counter = true;
+  reservation.name = name;
+  reservation.category = category;
+  reservation.unit_multiplier = unit_multiplier;
+  reservation.is_incremental = is_incremental;
+  // Incrementally encoded counters are only valid on a single sequence.
+  if (is_incremental)
+    reservation.packet_sequence_id = packet_sequence_id;
+
+  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
+  bool inserted;
+  std::tie(it, inserted) =
+      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
+
+  if (inserted || it->second.IsForSameTrack(reservation))
+    return;
+
+  // Counter tracks should not be reassigned to a different parent track later
+  // (neither should the type of the track change).
+  PERFETTO_DLOG("New track reservation for counter track with uuid %" PRIu64
+                " doesn't match earlier one",
+                uuid);
+  context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+}
+
+void TrackEventTracker::ReserveDescriptorChildTrack(uint64_t uuid,
+                                                    uint64_t parent_uuid,
+                                                    StringId name) {
+  DescriptorTrackReservation reservation;
+  reservation.parent_uuid = parent_uuid;
+  reservation.name = name;
+
+  std::map<uint64_t, DescriptorTrackReservation>::iterator it;
+  bool inserted;
+  std::tie(it, inserted) =
+      reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
+
+  if (inserted || it->second.IsForSameTrack(reservation))
+    return;
+
+  // Child tracks should not be reassigned to a different parent track later
+  // (neither should the type of the track change).
+  PERFETTO_DLOG("New track reservation for child track with uuid %" PRIu64
+                " doesn't match earlier one",
+                uuid);
+  context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+}
+
+base::Optional<TrackId> TrackEventTracker::GetDescriptorTrack(
+    uint64_t uuid,
+    StringId event_name) {
+  base::Optional<TrackId> track_id = GetDescriptorTrackImpl(uuid);
+  if (!track_id || event_name.is_null())
+    return track_id;
+
+  // Update the name of the track if unset and the track is not the primary
+  // track of a process/thread or a counter track.
+  auto* tracks = context_->storage->mutable_track_table();
+  uint32_t row = *tracks->id().IndexOf(*track_id);
+  if (!tracks->name()[row].is_null())
+    return track_id;
+
+  // Check reservation for track type.
+  auto reservation_it = reserved_descriptor_tracks_.find(uuid);
+  PERFETTO_CHECK(reservation_it != reserved_descriptor_tracks_.end());
+
+  if (reservation_it->second.pid || reservation_it->second.tid ||
+      reservation_it->second.is_counter) {
+    return track_id;
+  }
+  tracks->mutable_name()->Set(row, event_name);
+  return track_id;
+}
+
+base::Optional<TrackId> TrackEventTracker::GetDescriptorTrackImpl(
+    uint64_t uuid,
+    std::vector<uint64_t>* descendent_uuids) {
+  auto it = resolved_descriptor_tracks_.find(uuid);
+  if (it != resolved_descriptor_tracks_.end())
+    return it->second;
+
+  auto reservation_it = reserved_descriptor_tracks_.find(uuid);
+  if (reservation_it == reserved_descriptor_tracks_.end())
+    return base::nullopt;
+
+  TrackId track_id =
+      ResolveDescriptorTrack(uuid, reservation_it->second, descendent_uuids);
+  resolved_descriptor_tracks_[uuid] = track_id;
+  return track_id;
+}
+
+TrackId TrackEventTracker::ResolveDescriptorTrack(
+    uint64_t uuid,
+    const DescriptorTrackReservation& reservation,
+    std::vector<uint64_t>* descendent_uuids) {
+  auto set_track_name_and_return = [this, &reservation](TrackId track_id) {
+    if (reservation.name.is_null())
+      return track_id;
+
+    // Initialize the track name here, so that, if a name was given in the
+    // reservation, it is set immediately after resolution takes place.
+    auto* tracks = context_->storage->mutable_track_table();
+    tracks->mutable_name()->Set(*tracks->id().IndexOf(track_id),
+                                reservation.name);
+    return track_id;
+  };
+
+  static constexpr size_t kMaxAncestors = 10;
+
+  // Try to resolve any parent tracks recursively, too.
+  base::Optional<TrackId> parent_track_id;
+  if (reservation.parent_uuid) {
+    // Input data may contain loops or extremely long ancestor track chains. To
+    // avoid stack overflow in these situations, we keep track of the ancestors
+    // seen in the recursion.
+    std::unique_ptr<std::vector<uint64_t>> owned_descendent_uuids;
+    if (!descendent_uuids) {
+      owned_descendent_uuids.reset(new std::vector<uint64_t>());
+      descendent_uuids = owned_descendent_uuids.get();
+    }
+    descendent_uuids->push_back(uuid);
+
+    if (descendent_uuids->size() > kMaxAncestors) {
+      PERFETTO_ELOG(
+          "Too many ancestors in parent_track_uuid hierarchy at track %" PRIu64
+          " with parent %" PRIu64,
+          uuid, reservation.parent_uuid);
+    } else if (std::find(descendent_uuids->begin(), descendent_uuids->end(),
+                         reservation.parent_uuid) != descendent_uuids->end()) {
+      PERFETTO_ELOG(
+          "Loop detected in parent_track_uuid hierarchy at track %" PRIu64
+          " with parent %" PRIu64,
+          uuid, reservation.parent_uuid);
+    } else {
+      parent_track_id =
+          GetDescriptorTrackImpl(reservation.parent_uuid, descendent_uuids);
+      if (!parent_track_id) {
+        PERFETTO_ELOG("Unknown parent track %" PRIu64 " for track %" PRIu64,
+                      reservation.parent_uuid, uuid);
+      }
+    }
+
+    descendent_uuids->pop_back();
+    if (owned_descendent_uuids)
+      descendent_uuids = nullptr;
+  }
+
+  if (reservation.tid) {
+    UniqueTid utid = context_->process_tracker->UpdateThread(*reservation.tid,
+                                                             *reservation.pid);
+    auto it_and_inserted =
+        descriptor_uuids_by_utid_.insert(std::make_pair<>(utid, uuid));
+    if (!it_and_inserted.second) {
+      // We already saw a another track with a different uuid for this thread.
+      // Since there should only be one descriptor track for each thread, we
+      // assume that its tid was reused. So, start a new thread.
+      uint64_t old_uuid = it_and_inserted.first->second;
+      PERFETTO_DCHECK(old_uuid != uuid);  // Every track is only resolved once.
+
+      PERFETTO_DLOG("Detected tid reuse (pid: %" PRIu32 " tid: %" PRIu32
+                    ") from track descriptors (old uuid: %" PRIu64
+                    " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
+                    *reservation.pid, *reservation.tid, old_uuid, uuid,
+                    reservation.min_timestamp);
+
+      utid = context_->process_tracker->StartNewThread(base::nullopt,
+                                                       *reservation.tid);
+
+      // Associate the new thread with its process.
+      PERFETTO_CHECK(context_->process_tracker->UpdateThread(
+                         *reservation.tid, *reservation.pid) == utid);
+
+      descriptor_uuids_by_utid_[utid] = uuid;
+    }
+    return set_track_name_and_return(
+        context_->track_tracker->InternThreadTrack(utid));
+  }
+
+  if (reservation.pid) {
+    UniquePid upid =
+        context_->process_tracker->GetOrCreateProcess(*reservation.pid);
+    auto it_and_inserted =
+        descriptor_uuids_by_upid_.insert(std::make_pair<>(upid, uuid));
+    if (!it_and_inserted.second) {
+      // We already saw a another track with a different uuid for this process.
+      // Since there should only be one descriptor track for each process, we
+      // assume that its pid was reused. So, start a new process.
+      uint64_t old_uuid = it_and_inserted.first->second;
+      PERFETTO_DCHECK(old_uuid != uuid);  // Every track is only resolved once.
+
+      PERFETTO_DLOG("Detected pid reuse (pid: %" PRIu32
+                    ") from track descriptors (old uuid: %" PRIu64
+                    " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
+                    *reservation.pid, old_uuid, uuid,
+                    reservation.min_timestamp);
+
+      upid = context_->process_tracker->StartNewProcess(
+          base::nullopt, base::nullopt, *reservation.pid, kNullStringId);
+
+      descriptor_uuids_by_upid_[upid] = uuid;
+    }
+    return set_track_name_and_return(
+        context_->track_tracker->InternProcessTrack(upid));
+  }
+
+  base::Optional<TrackId> track_id;
+  if (parent_track_id) {
+    // If parent is a thread track, create another thread-associated track.
+    auto* thread_tracks = context_->storage->mutable_thread_track_table();
+    base::Optional<uint32_t> thread_track_index =
+        thread_tracks->id().IndexOf(*parent_track_id);
+    if (thread_track_index) {
+      if (reservation.is_counter) {
+        // Thread counter track.
+        auto* thread_counter_tracks =
+            context_->storage->mutable_thread_counter_track_table();
+        tables::ThreadCounterTrackTable::Row row;
+        row.utid = thread_tracks->utid()[*thread_track_index];
+        track_id = thread_counter_tracks->Insert(row).id;
+      } else {
+        // Thread slice track.
+        tables::ThreadTrackTable::Row row;
+        row.utid = thread_tracks->utid()[*thread_track_index];
+        track_id = thread_tracks->Insert(row).id;
+      }
+    } else {
+      // If parent is a process track, create another process-associated track.
+      auto* process_tracks = context_->storage->mutable_process_track_table();
+      base::Optional<uint32_t> process_track_index =
+          process_tracks->id().IndexOf(*parent_track_id);
+      if (process_track_index) {
+        if (reservation.is_counter) {
+          // Process counter track.
+          auto* process_counter_tracks =
+              context_->storage->mutable_process_counter_track_table();
+          tables::ProcessCounterTrackTable::Row row;
+          row.upid = process_tracks->upid()[*process_track_index];
+          track_id = process_counter_tracks->Insert(row).id;
+        } else {
+          // Process slice track.
+          tables::ProcessTrackTable::Row row;
+          row.upid = process_tracks->upid()[*process_track_index];
+          track_id = process_tracks->Insert(row).id;
+        }
+      }
+    }
+  }
+
+  // Otherwise create a global track.
+  if (!track_id) {
+    if (reservation.is_counter) {
+      // Global counter track.
+      tables::CounterTrackTable::Row row;
+      track_id =
+          context_->storage->mutable_counter_track_table()->Insert(row).id;
+    } else {
+      // Global slice track.
+      tables::TrackTable::Row row;
+      track_id = context_->storage->mutable_track_table()->Insert(row).id;
+    }
+    // The global track with no uuid is the default global track (e.g. for
+    // global instant events). Any other global tracks are considered children
+    // of the default track.
+    if (!parent_track_id && uuid) {
+      // Detect loops where the default track has a parent that itself is a
+      // global track (and thus should be parent of the default track).
+      if (descendent_uuids &&
+          std::find(descendent_uuids->begin(), descendent_uuids->end(),
+                    kDefaultDescriptorTrackUuid) != descendent_uuids->end()) {
+        PERFETTO_ELOG(
+            "Loop detected in parent_track_uuid hierarchy at track %" PRIu64
+            " with parent %" PRIu64,
+            uuid, kDefaultDescriptorTrackUuid);
+      } else {
+        parent_track_id = GetOrCreateDefaultDescriptorTrack();
+      }
+    }
+  }
+
+  auto args = context_->args_tracker->AddArgsTo(*track_id);
+  args.AddArg(source_key_, Variadic::String(descriptor_source_))
+      .AddArg(source_id_key_, Variadic::Integer(static_cast<int64_t>(uuid)));
+  if (parent_track_id) {
+    args.AddArg(parent_track_id_key_,
+                Variadic::Integer(parent_track_id->value));
+  }
+  if (reservation.category != kNullStringId) {
+    args.AddArg(category_key_, Variadic::String(reservation.category));
+  }
+  return set_track_name_and_return(*track_id);
+}
+
+TrackId TrackEventTracker::GetOrCreateDefaultDescriptorTrack() {
+  // If the default track was already reserved (e.g. because a producer emitted
+  // a descriptor for it) or created, resolve and return it.
+  base::Optional<TrackId> track_id =
+      GetDescriptorTrack(kDefaultDescriptorTrackUuid);
+  if (track_id)
+    return *track_id;
+
+  // Otherwise reserve a new track and resolve it.
+  ReserveDescriptorChildTrack(kDefaultDescriptorTrackUuid, /*parent_uuid=*/0,
+                              default_descriptor_track_name_);
+  return *GetDescriptorTrack(kDefaultDescriptorTrackUuid);
+}
+
+base::Optional<int64_t> TrackEventTracker::ConvertToAbsoluteCounterValue(
+    uint64_t counter_track_uuid,
+    uint32_t packet_sequence_id,
+    int64_t value) {
+  auto reservation_it = reserved_descriptor_tracks_.find(counter_track_uuid);
+  if (reservation_it == reserved_descriptor_tracks_.end()) {
+    PERFETTO_DLOG("Unknown counter track with uuid %" PRIu64,
+                  counter_track_uuid);
+    return base::nullopt;
+  }
+
+  DescriptorTrackReservation& reservation = reservation_it->second;
+  if (!reservation.is_counter) {
+    PERFETTO_DLOG("Track with uuid %" PRIu64 " is not a counter track",
+                  counter_track_uuid);
+    return base::nullopt;
+  }
+
+  if (reservation.unit_multiplier > 0)
+    value *= reservation.unit_multiplier;
+
+  if (reservation.is_incremental) {
+    if (reservation.packet_sequence_id != packet_sequence_id) {
+      PERFETTO_DLOG(
+          "Incremental counter track with uuid %" PRIu64
+          " was updated from the wrong packet sequence (expected: %" PRIu32
+          " got:%" PRIu32 ")",
+          counter_track_uuid, reservation.packet_sequence_id,
+          packet_sequence_id);
+      return base::nullopt;
+    }
+
+    reservation.latest_value += value;
+    value = reservation.latest_value;
+  }
+
+  return value;
+}
+
+void TrackEventTracker::OnIncrementalStateCleared(uint32_t packet_sequence_id) {
+  // TODO(eseckler): Improve on the runtime complexity of this. At O(hundreds)
+  // of packet sequences, incremental state clearing at O(trace second), and
+  // total number of tracks in O(thousands), a linear scan through all tracks
+  // here might not be fast enough.
+  for (auto& entry : reserved_descriptor_tracks_) {
+    DescriptorTrackReservation& reservation = entry.second;
+    // Only consider incremental counter tracks for current sequence.
+    if (!reservation.is_counter || !reservation.is_incremental ||
+        reservation.packet_sequence_id != packet_sequence_id) {
+      continue;
+    }
+    // Reset their value to 0, see CounterDescriptor's |is_incremental|.
+    reservation.latest_value = 0;
+  }
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/track_event_tracker.h b/src/trace_processor/importers/proto/track_event_tracker.h
new file mode 100644
index 0000000..6a13ac9
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_tracker.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 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_TRACKER_H_
+#define 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"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Tracks and stores tracks based on track types, ids and scopes.
+class TrackEventTracker {
+ public:
+  explicit TrackEventTracker(TraceProcessorContext*);
+
+  // Associate a TrackDescriptor track identified by the given |uuid| with a
+  // process's |pid|. This is called during tokenization. If a reservation for
+  // the same |uuid| already exists, verifies that the present reservation
+  // matches the new one.
+  //
+  // The track will be resolved to the process track (see InternProcessTrack())
+  // upon the first call to GetDescriptorTrack() with the same |uuid|. At this
+  // time, |pid| will also be resolved to a |upid|.
+  void ReserveDescriptorProcessTrack(uint64_t uuid,
+                                     StringId name,
+                                     uint32_t pid,
+                                     int64_t timestamp);
+
+  // Associate a TrackDescriptor track identified by the given |uuid| with a
+  // thread's |pid| and |tid|. This is called during tokenization. If a
+  // reservation for the same |uuid| already exists, verifies that the present
+  // reservation matches the new one.
+  //
+  // The track will be resolved to the thread track (see InternThreadTrack())
+  // upon the first call to GetDescriptorTrack() with the same |uuid|. At this
+  // time, |pid| will also be resolved to a |upid|.
+  void ReserveDescriptorThreadTrack(uint64_t uuid,
+                                    uint64_t parent_uuid,
+                                    StringId name,
+                                    uint32_t pid,
+                                    uint32_t tid,
+                                    int64_t timestamp);
+
+  // Associate a TrackDescriptor track identified by the given |uuid| with a
+  // parent track (usually a process- or thread-associated track). This is
+  // called during tokenization. If a reservation for the same |uuid| already
+  // exists, will attempt to update it.
+  //
+  // The track will be created upon the first call to GetDescriptorTrack() with
+  // the same |uuid|. If |parent_uuid| is 0, the track will become a global
+  // track. Otherwise, it will become a new track of the same type as its parent
+  // track.
+  void ReserveDescriptorChildTrack(uint64_t uuid,
+                                   uint64_t parent_uuid,
+                                   StringId name);
+
+  // Associate a counter-type TrackDescriptor track identified by the given
+  // |uuid| with a parent track (usually a process or thread track). This is
+  // called during tokenization. If a reservation for the same |uuid| already
+  // exists, will attempt to update it. The provided |category| will be stored
+  // into the track's args.
+  //
+  // If |is_incremental| is true, the counter will only be valid on the packet
+  // sequence identified by |packet_sequence_id|. |unit_multiplier| is an
+  // optional multiplication factor applied to counter values. Values for the
+  // counter will be translated during tokenization via
+  // ConvertToAbsoluteCounterValue().
+  //
+  // The track will be created upon the first call to GetDescriptorTrack() with
+  // the same |uuid|. If |parent_uuid| is 0, the track will become a global
+  // track. Otherwise, it will become a new counter track for the same
+  // process/thread as its parent track.
+  void ReserveDescriptorCounterTrack(uint64_t uuid,
+                                     uint64_t parent_uuid,
+                                     StringId name,
+                                     StringId category,
+                                     int64_t unit_multiplier,
+                                     bool is_incremental,
+                                     uint32_t packet_sequence_id);
+
+  // Returns the ID of the track for the TrackDescriptor with the given |uuid|.
+  // This is called during parsing. The first call to GetDescriptorTrack() for
+  // each |uuid| resolves and inserts the track (and its parent tracks,
+  // following the parent_uuid chain recursively) based on reservations made for
+  // the |uuid|. If the track is a child track and doesn't have a name yet,
+  // updates the track's name to event_name. Returns nullopt if no track for a
+  // descriptor with this |uuid| has been reserved.
+  // TODO(lalitm): this method needs to be split up and moved back to
+  // TrackTracker.
+  base::Optional<TrackId> GetDescriptorTrack(
+      uint64_t uuid,
+      StringId event_name = kNullStringId);
+
+  // Converts the given counter value to an absolute value in the unit of the
+  // counter, applying incremental delta encoding or unit multipliers as
+  // necessary. If the counter uses incremental encoding, |packet_sequence_id|
+  // must match the one in its track reservation. Returns base::nullopt if the
+  // counter track is unknown or an invalid |packet_sequence_id| was passed.
+  base::Optional<int64_t> ConvertToAbsoluteCounterValue(
+      uint64_t counter_track_uuid,
+      uint32_t packet_sequence_id,
+      int64_t value);
+
+  // Returns the ID of the implicit trace-global default TrackDescriptor track.
+  // TODO(lalitm): this method needs to be moved back to TrackTracker once
+  // GetDescriptorTrack is moved back.
+  TrackId GetOrCreateDefaultDescriptorTrack();
+
+  // Called by ProtoTraceReader whenever incremental state is cleared on a
+  // packet sequence. Resets counter values for any incremental counters of
+  // the sequence identified by |packet_sequence_id|.
+  void OnIncrementalStateCleared(uint32_t packet_sequence_id);
+
+ private:
+  struct DescriptorTrackReservation {
+    uint64_t parent_uuid = 0;
+    base::Optional<uint32_t> pid;
+    base::Optional<uint32_t> tid;
+    int64_t min_timestamp = 0;  // only set if |pid| and/or |tid| is set.
+    StringId name = kNullStringId;
+
+    // For counter tracks.
+    bool is_counter = false;
+    StringId category = kNullStringId;
+    int64_t unit_multiplier = 1;
+    bool is_incremental = false;
+    uint32_t packet_sequence_id = 0;
+    int64_t latest_value = 0;
+
+    // Whether |other| is a valid descriptor for this track reservation. A track
+    // should always remain nested underneath its original parent.
+    bool IsForSameTrack(const DescriptorTrackReservation& other) {
+      // Note that |min_timestamp|, |latest_value|, and |name| are ignored for
+      // this comparison.
+      return std::tie(parent_uuid, pid, tid, is_counter, category,
+                      unit_multiplier, is_incremental, packet_sequence_id) ==
+             std::tie(other.parent_uuid, pid, tid, is_counter, category,
+                      unit_multiplier, is_incremental, packet_sequence_id);
+    }
+  };
+
+  base::Optional<TrackId> GetDescriptorTrackImpl(
+      uint64_t uuid,
+      std::vector<uint64_t>* descendent_uuids = nullptr);
+  TrackId ResolveDescriptorTrack(uint64_t uuid,
+                                 const DescriptorTrackReservation&,
+                                 std::vector<uint64_t>* descendent_uuids);
+
+  static constexpr uint64_t kDefaultDescriptorTrackUuid = 0u;
+
+  std::map<UniqueTid, TrackId> thread_tracks_;
+  std::map<UniquePid, TrackId> process_tracks_;
+
+  std::map<uint64_t /* uuid */, DescriptorTrackReservation>
+      reserved_descriptor_tracks_;
+  std::map<uint64_t /* uuid */, TrackId> resolved_descriptor_tracks_;
+
+  // Stores the descriptor uuid used for the primary process/thread track
+  // for the given upid / utid. Used for pid/tid reuse detection.
+  std::map<UniquePid, uint64_t /*uuid*/> descriptor_uuids_by_upid_;
+  std::map<UniqueTid, uint64_t /*uuid*/> descriptor_uuids_by_utid_;
+
+  const StringId source_key_ = kNullStringId;
+  const StringId source_id_key_ = kNullStringId;
+  const StringId parent_track_id_key_ = kNullStringId;
+  const StringId category_key_ = kNullStringId;
+
+  const StringId descriptor_source_ = kNullStringId;
+
+  const StringId default_descriptor_track_name_ = kNullStringId;
+
+  TraceProcessorContext* const context_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TRACKER_H_