Merge "Update chrome_tasks test"
diff --git a/Android.bp b/Android.bp
index 1953510..b65d3fe 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13321,9 +13321,9 @@
         "src/traced/probes/main.cc",
     ],
     shared_libs: [
-        "liblog",
         "libperfetto",
     ],
+    host_supported: true,
     defaults: [
         "perfetto_defaults",
     ],
@@ -13333,6 +13333,13 @@
         "traced_perf",
         "trigger_perfetto",
     ],
+    target: {
+        android: {
+            shared_libs: [
+                "liblog",
+            ],
+        },
+    },
 }
 
 // GN: //src/perfetto_cmd:trigger_perfetto
diff --git a/BUILD b/BUILD
index 81affad..a62edb8 100644
--- a/BUILD
+++ b/BUILD
@@ -1278,6 +1278,7 @@
     name = "src_trace_processor_db_overlays_overlays",
     srcs = [
         "src/trace_processor/db/overlays/storage_overlay.h",
+        "src/trace_processor/db/overlays/types.h",
     ],
 )
 
diff --git a/include/perfetto/tracing/internal/track_event_data_source.h b/include/perfetto/tracing/internal/track_event_data_source.h
index d1e17a6..2ec348e 100644
--- a/include/perfetto/tracing/internal/track_event_data_source.h
+++ b/include/perfetto/tracing/internal/track_event_data_source.h
@@ -308,276 +308,25 @@
         {category_index});
   }
 
-  // Once we've determined tracing to be enabled for this category, actually
-  // write a trace event onto this thread's default track. Outlined to avoid
-  // bloating code (mostly stack depth) at the actual trace point.
-  //
-  // The following combination of parameters is supported (in the given order):
-  // - Zero or one track,
-  // - Zero or one custom timestamp,
-  // - Arbitrary number of debug annotations.
-  // - Zero or one lambda.
-
-  // Trace point which does not take a track or timestamp.
-  template <typename CategoryType,
-            typename EventNameType,
-            typename... Arguments>
-  static void TraceForCategory(uint32_t instances,
-                               const CategoryType& category,
-                               const EventNameType& event_name,
-                               perfetto::protos::pbzero::TrackEvent::Type type,
-                               Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(instances, category, event_name, type,
-                         TrackEventInternal::kDefaultTrack,
-                         TrackEventInternal::GetTraceTime(),
-                         std::forward<Arguments>(args)...);
+  // The following methods forward all arguments to TraceForCategoryBody
+  // while casting string constants to const char*.
+  template <typename... Arguments>
+  static void TraceForCategory(Arguments&&... args) PERFETTO_ALWAYS_INLINE {
+    TraceForCategoryBody(DecayStrType(args)...);
   }
 
-  // Trace point which takes a track, but not timestamp.
-  // NOTE: Here track should be captured using universal reference (TrackType&&)
-  // instead of const TrackType& to ensure that the proper overload is selected
-  // (otherwise the compiler will fail to disambiguate between adding const& and
-  // parsing track as a part of Arguments...).
-  template <typename TrackType,
-            typename CategoryType,
-            typename EventNameType,
-            typename... Arguments,
-            typename TrackTypeCheck = typename std::enable_if<
-                std::is_convertible<TrackType, Track>::value>::type>
-  static void TraceForCategory(uint32_t instances,
-                               const CategoryType& category,
-                               const EventNameType& event_name,
-                               perfetto::protos::pbzero::TrackEvent::Type type,
-                               TrackType&& track,
-                               Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(
-        instances, category, event_name, type, std::forward<TrackType>(track),
-        TrackEventInternal::GetTraceTime(), std::forward<Arguments>(args)...);
+  template <typename... Arguments>
+  static void TraceForCategoryLegacy(Arguments&&... args)
+      PERFETTO_ALWAYS_INLINE {
+    TraceForCategoryLegacyBody(DecayStrType(args)...);
   }
 
-  // Trace point which takes a timestamp, but not track.
-  template <typename CategoryType,
-            typename EventNameType,
-            typename TimestampType = uint64_t,
-            typename... Arguments,
-            typename TimestampTypeCheck = typename std::enable_if<
-                IsValidTimestamp<TimestampType>()>::type>
-  static void TraceForCategory(uint32_t instances,
-                               const CategoryType& category,
-                               const EventNameType& event_name,
-                               perfetto::protos::pbzero::TrackEvent::Type type,
-                               TimestampType&& timestamp,
-                               Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(instances, category, event_name, type,
-                         TrackEventInternal::kDefaultTrack,
-                         std::forward<TimestampType>(timestamp),
-                         std::forward<Arguments>(args)...);
+  template <typename... Arguments>
+  static void TraceForCategoryLegacyWithId(Arguments&&... args)
+      PERFETTO_ALWAYS_INLINE {
+    TraceForCategoryLegacyWithIdBody(DecayStrType(args)...);
   }
 
-  // Trace point which takes a timestamp and a track.
-  template <typename TrackType,
-            typename CategoryType,
-            typename EventNameType,
-            typename TimestampType = uint64_t,
-            typename... Arguments,
-            typename TrackTypeCheck = typename std::enable_if<
-                std::is_convertible<TrackType, Track>::value>::type,
-            typename TimestampTypeCheck = typename std::enable_if<
-                IsValidTimestamp<TimestampType>()>::type>
-  static void TraceForCategory(uint32_t instances,
-                               const CategoryType& category,
-                               const EventNameType& event_name,
-                               perfetto::protos::pbzero::TrackEvent::Type type,
-                               TrackType&& track,
-                               TimestampType&& timestamp,
-                               Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(instances, category, event_name, type,
-                         std::forward<TrackType>(track),
-                         std::forward<TimestampType>(timestamp),
-                         std::forward<Arguments>(args)...);
-  }
-
-  // Trace point with with a counter sample.
-  template <typename CategoryType, typename EventNameType, typename ValueType>
-  static void TraceForCategory(uint32_t instances,
-                               const CategoryType& category,
-                               const EventNameType&,
-                               perfetto::protos::pbzero::TrackEvent::Type type,
-                               CounterTrack track,
-                               ValueType value) PERFETTO_ALWAYS_INLINE {
-    PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER);
-    TraceForCategory(instances, category, /*name=*/nullptr, type, track,
-                     TrackEventInternal::GetTraceTime(), value);
-  }
-
-  // Trace point with with a timestamp and a counter sample.
-  template <typename CategoryType,
-            typename EventNameType,
-            typename TimestampType = uint64_t,
-            typename TimestampTypeCheck = typename std::enable_if<
-                IsValidTimestamp<TimestampType>()>::type,
-            typename ValueType>
-  static void TraceForCategory(uint32_t instances,
-                               const CategoryType& category,
-                               const EventNameType&,
-                               perfetto::protos::pbzero::TrackEvent::Type type,
-                               CounterTrack track,
-                               TimestampType timestamp,
-                               ValueType value) PERFETTO_ALWAYS_INLINE {
-    PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER);
-    TraceForCategoryImpl(
-        instances, category, /*name=*/nullptr, type, track, timestamp,
-        [&](EventContext event_ctx) {
-          if (std::is_integral<ValueType>::value) {
-            int64_t value_int64 = static_cast<int64_t>(value);
-            if (track.is_incremental()) {
-              TrackEventIncrementalState* incr_state =
-                  event_ctx.GetIncrementalState();
-              PERFETTO_DCHECK(incr_state != nullptr);
-              auto prv_value =
-                  incr_state->last_counter_value_per_track[track.uuid];
-              event_ctx.event()->set_counter_value(value_int64 - prv_value);
-              prv_value = value_int64;
-              incr_state->last_counter_value_per_track[track.uuid] = prv_value;
-            } else {
-              event_ctx.event()->set_counter_value(value_int64);
-            }
-          } else {
-            event_ctx.event()->set_double_counter_value(
-                static_cast<double>(value));
-          }
-        });
-  }
-
-// Additional trace points used in legacy macros.
-// It's possible to implement legacy macros using a common TraceForCategory,
-// by supplying a lambda that sets all necessary legacy fields. But this
-// results in a binary size bloat because every trace point generates its own
-// template instantiation with its own lambda. ICF can't eliminate those as
-// each lambda captures different variables and so the code is not completely
-// identical.
-// What we do instead is define additional TraceForCategoryLegacy templates
-// that take legacy arguments directly. Their instantiations can have the same
-// binary code for at least some macro invocations and so can be successfully
-// folded by the linker.
-#if PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
-  template <typename TrackType,
-            typename CategoryType,
-            typename EventNameType,
-            typename... Arguments,
-            typename TrackTypeCheck = typename std::enable_if<
-                std::is_convertible<TrackType, Track>::value>::type>
-  static void TraceForCategoryLegacy(
-      uint32_t instances,
-      const CategoryType& category,
-      const EventNameType& event_name,
-      perfetto::protos::pbzero::TrackEvent::Type type,
-      TrackType&& track,
-      char phase,
-      uint32_t flags,
-      Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(instances, category, event_name, type, track,
-                         TrackEventInternal::GetTraceTime(),
-                         [&](perfetto::EventContext ctx)
-                             PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
-                               using ::perfetto::internal::TrackEventLegacy;
-                               TrackEventLegacy::WriteLegacyEvent(
-                                   std::move(ctx), phase, flags, args...);
-                             });
-  }
-
-  template <typename TrackType,
-            typename CategoryType,
-            typename EventNameType,
-            typename TimestampType = uint64_t,
-            typename... Arguments,
-            typename TrackTypeCheck = typename std::enable_if<
-                std::is_convertible<TrackType, Track>::value>::type,
-            typename TimestampTypeCheck = typename std::enable_if<
-                IsValidTimestamp<TimestampType>()>::type>
-  static void TraceForCategoryLegacy(
-      uint32_t instances,
-      const CategoryType& category,
-      const EventNameType& event_name,
-      perfetto::protos::pbzero::TrackEvent::Type type,
-      TrackType&& track,
-      char phase,
-      uint32_t flags,
-      TimestampType&& timestamp,
-      Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(
-        instances, category, event_name, type, track, timestamp,
-        [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
-          using ::perfetto::internal::TrackEventLegacy;
-          TrackEventLegacy::WriteLegacyEvent(std::move(ctx), phase, flags,
-                                             args...);
-        });
-  }
-
-  template <typename TrackType,
-            typename CategoryType,
-            typename EventNameType,
-            typename ThreadIdType,
-            typename LegacyIdType,
-            typename... Arguments,
-            typename TrackTypeCheck = typename std::enable_if<
-                std::is_convertible<TrackType, Track>::value>::type>
-  static void TraceForCategoryLegacyWithId(
-      uint32_t instances,
-      const CategoryType& category,
-      const EventNameType& event_name,
-      perfetto::protos::pbzero::TrackEvent::Type type,
-      TrackType&& track,
-      char phase,
-      uint32_t flags,
-      ThreadIdType thread_id,
-      LegacyIdType legacy_id,
-      Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(
-        instances, category, event_name, type, track,
-        TrackEventInternal::GetTraceTime(),
-        [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
-          using ::perfetto::internal::TrackEventLegacy;
-          ::perfetto::internal::LegacyTraceId trace_id{legacy_id};
-          TrackEventLegacy::WriteLegacyEventWithIdAndTid(
-              std::move(ctx), phase, flags, trace_id, thread_id, args...);
-        });
-  }
-
-  template <typename TrackType,
-            typename CategoryType,
-            typename EventNameType,
-            typename ThreadIdType,
-            typename LegacyIdType,
-            typename TimestampType = uint64_t,
-            typename... Arguments,
-            typename TrackTypeCheck = typename std::enable_if<
-                std::is_convertible<TrackType, Track>::value>::type,
-            typename TimestampTypeCheck = typename std::enable_if<
-                IsValidTimestamp<TimestampType>()>::type>
-  static void TraceForCategoryLegacyWithId(
-      uint32_t instances,
-      const CategoryType& category,
-      const EventNameType& event_name,
-      perfetto::protos::pbzero::TrackEvent::Type type,
-      TrackType&& track,
-      char phase,
-      uint32_t flags,
-      ThreadIdType thread_id,
-      LegacyIdType legacy_id,
-      TimestampType&& timestamp,
-      Arguments&&... args) PERFETTO_NO_INLINE {
-    TraceForCategoryImpl(
-        instances, category, event_name, type, track, timestamp,
-        [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
-          using ::perfetto::internal::TrackEventLegacy;
-          ::perfetto::internal::LegacyTraceId trace_id{legacy_id};
-          TrackEventLegacy::WriteLegacyEventWithIdAndTid(
-              std::move(ctx), phase, flags, trace_id, thread_id, args...);
-        });
-  }
-#endif  // PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
-
   // Initialize the track event library. Should be called before tracing is
   // enabled.
   static bool Register() {
@@ -638,6 +387,295 @@
   const protos::gen::TrackEventConfig& GetConfig() const { return config_; }
 
  private:
+  // The DecayStrType method is used to avoid unnecessary instantiations of
+  // templates on string constants of different sizes. Without it, strings
+  // of different lengths have different types: char[10], char[15] etc.
+  // DecayStrType forwards all types of arguments as is, with the exception
+  // of string constants which are all cast to const char*. This allows to
+  // avoid extra instantiations of TraceForCategory templates.
+  template <typename T>
+  static T&& DecayStrType(T&& t) {
+    return std::forward<T>(t);
+  }
+
+  static const char* DecayStrType(const char* t) { return t; }
+
+  // Once we've determined tracing to be enabled for this category, actually
+  // write a trace event onto this thread's default track. Outlined to avoid
+  // bloating code (mostly stack depth) at the actual trace point.
+  //
+  // The following combination of parameters is supported (in the given order):
+  // - Zero or one track,
+  // - Zero or one custom timestamp,
+  // - Arbitrary number of debug annotations.
+  // - Zero or one lambda.
+
+  // Trace point which does not take a track or timestamp.
+  template <typename CategoryType,
+            typename EventNameType,
+            typename... Arguments>
+  static void TraceForCategoryBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(instances, category, event_name, type,
+                         TrackEventInternal::kDefaultTrack,
+                         TrackEventInternal::GetTraceTime(),
+                         std::forward<Arguments>(args)...);
+  }
+
+  // Trace point which takes a track, but not timestamp.
+  // NOTE: Here track should be captured using universal reference (TrackType&&)
+  // instead of const TrackType& to ensure that the proper overload is selected
+  // (otherwise the compiler will fail to disambiguate between adding const& and
+  // parsing track as a part of Arguments...).
+  template <typename TrackType,
+            typename CategoryType,
+            typename EventNameType,
+            typename... Arguments,
+            typename TrackTypeCheck = typename std::enable_if<
+                std::is_convertible<TrackType, Track>::value>::type>
+  static void TraceForCategoryBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      TrackType&& track,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(
+        instances, category, event_name, type, std::forward<TrackType>(track),
+        TrackEventInternal::GetTraceTime(), std::forward<Arguments>(args)...);
+  }
+
+  // Trace point which takes a timestamp, but not track.
+  template <typename CategoryType,
+            typename EventNameType,
+            typename TimestampType = uint64_t,
+            typename... Arguments,
+            typename TimestampTypeCheck = typename std::enable_if<
+                IsValidTimestamp<TimestampType>()>::type>
+  static void TraceForCategoryBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      TimestampType&& timestamp,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(instances, category, event_name, type,
+                         TrackEventInternal::kDefaultTrack,
+                         std::forward<TimestampType>(timestamp),
+                         std::forward<Arguments>(args)...);
+  }
+
+  // Trace point which takes a timestamp and a track.
+  template <typename TrackType,
+            typename CategoryType,
+            typename EventNameType,
+            typename TimestampType = uint64_t,
+            typename... Arguments,
+            typename TrackTypeCheck = typename std::enable_if<
+                std::is_convertible<TrackType, Track>::value>::type,
+            typename TimestampTypeCheck = typename std::enable_if<
+                IsValidTimestamp<TimestampType>()>::type>
+  static void TraceForCategoryBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      TrackType&& track,
+      TimestampType&& timestamp,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(instances, category, event_name, type,
+                         std::forward<TrackType>(track),
+                         std::forward<TimestampType>(timestamp),
+                         std::forward<Arguments>(args)...);
+  }
+
+  // Trace point with with a counter sample.
+  template <typename CategoryType, typename EventNameType, typename ValueType>
+  static void TraceForCategoryBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType&,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      CounterTrack track,
+      ValueType value) PERFETTO_ALWAYS_INLINE {
+    PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER);
+    TraceForCategory(instances, category, /*name=*/nullptr, type, track,
+                     TrackEventInternal::GetTraceTime(), value);
+  }
+
+  // Trace point with with a timestamp and a counter sample.
+  template <typename CategoryType,
+            typename EventNameType,
+            typename TimestampType = uint64_t,
+            typename TimestampTypeCheck = typename std::enable_if<
+                IsValidTimestamp<TimestampType>()>::type,
+            typename ValueType>
+  static void TraceForCategoryBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType&,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      CounterTrack track,
+      TimestampType timestamp,
+      ValueType value) PERFETTO_ALWAYS_INLINE {
+    PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER);
+    TraceForCategoryImpl(
+        instances, category, /*name=*/nullptr, type, track, timestamp,
+        [&](EventContext event_ctx) {
+          if (std::is_integral<ValueType>::value) {
+            int64_t value_int64 = static_cast<int64_t>(value);
+            if (track.is_incremental()) {
+              TrackEventIncrementalState* incr_state =
+                  event_ctx.GetIncrementalState();
+              PERFETTO_DCHECK(incr_state != nullptr);
+              auto prv_value =
+                  incr_state->last_counter_value_per_track[track.uuid];
+              event_ctx.event()->set_counter_value(value_int64 - prv_value);
+              prv_value = value_int64;
+              incr_state->last_counter_value_per_track[track.uuid] = prv_value;
+            } else {
+              event_ctx.event()->set_counter_value(value_int64);
+            }
+          } else {
+            event_ctx.event()->set_double_counter_value(
+                static_cast<double>(value));
+          }
+        });
+  }
+
+// Additional trace points used in legacy macros.
+// It's possible to implement legacy macros using a common TraceForCategory,
+// by supplying a lambda that sets all necessary legacy fields. But this
+// results in a binary size bloat because every trace point generates its own
+// template instantiation with its own lambda. ICF can't eliminate those as
+// each lambda captures different variables and so the code is not completely
+// identical.
+// What we do instead is define additional TraceForCategoryLegacy templates
+// that take legacy arguments directly. Their instantiations can have the same
+// binary code for at least some macro invocations and so can be successfully
+// folded by the linker.
+#if PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
+  template <typename TrackType,
+            typename CategoryType,
+            typename EventNameType,
+            typename... Arguments,
+            typename TrackTypeCheck = typename std::enable_if<
+                std::is_convertible<TrackType, Track>::value>::type>
+  static void TraceForCategoryLegacyBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      TrackType&& track,
+      char phase,
+      uint32_t flags,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(instances, category, event_name, type, track,
+                         TrackEventInternal::GetTraceTime(),
+                         [&](perfetto::EventContext ctx)
+                             PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
+                               using ::perfetto::internal::TrackEventLegacy;
+                               TrackEventLegacy::WriteLegacyEvent(
+                                   std::move(ctx), phase, flags, args...);
+                             });
+  }
+
+  template <typename TrackType,
+            typename CategoryType,
+            typename EventNameType,
+            typename TimestampType = uint64_t,
+            typename... Arguments,
+            typename TrackTypeCheck = typename std::enable_if<
+                std::is_convertible<TrackType, Track>::value>::type,
+            typename TimestampTypeCheck = typename std::enable_if<
+                IsValidTimestamp<TimestampType>()>::type>
+  static void TraceForCategoryLegacyBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      TrackType&& track,
+      char phase,
+      uint32_t flags,
+      TimestampType&& timestamp,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(
+        instances, category, event_name, type, track, timestamp,
+        [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
+          using ::perfetto::internal::TrackEventLegacy;
+          TrackEventLegacy::WriteLegacyEvent(std::move(ctx), phase, flags,
+                                             args...);
+        });
+  }
+
+  template <typename TrackType,
+            typename CategoryType,
+            typename EventNameType,
+            typename ThreadIdType,
+            typename LegacyIdType,
+            typename... Arguments,
+            typename TrackTypeCheck = typename std::enable_if<
+                std::is_convertible<TrackType, Track>::value>::type>
+  static void TraceForCategoryLegacyWithIdBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      TrackType&& track,
+      char phase,
+      uint32_t flags,
+      ThreadIdType thread_id,
+      LegacyIdType legacy_id,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(
+        instances, category, event_name, type, track,
+        TrackEventInternal::GetTraceTime(),
+        [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
+          using ::perfetto::internal::TrackEventLegacy;
+          ::perfetto::internal::LegacyTraceId trace_id{legacy_id};
+          TrackEventLegacy::WriteLegacyEventWithIdAndTid(
+              std::move(ctx), phase, flags, trace_id, thread_id, args...);
+        });
+  }
+
+  template <typename TrackType,
+            typename CategoryType,
+            typename EventNameType,
+            typename ThreadIdType,
+            typename LegacyIdType,
+            typename TimestampType = uint64_t,
+            typename... Arguments,
+            typename TrackTypeCheck = typename std::enable_if<
+                std::is_convertible<TrackType, Track>::value>::type,
+            typename TimestampTypeCheck = typename std::enable_if<
+                IsValidTimestamp<TimestampType>()>::type>
+  static void TraceForCategoryLegacyWithIdBody(
+      uint32_t instances,
+      const CategoryType& category,
+      const EventNameType& event_name,
+      perfetto::protos::pbzero::TrackEvent::Type type,
+      TrackType&& track,
+      char phase,
+      uint32_t flags,
+      ThreadIdType thread_id,
+      LegacyIdType legacy_id,
+      TimestampType&& timestamp,
+      Arguments&&... args) PERFETTO_NO_INLINE {
+    TraceForCategoryImpl(
+        instances, category, event_name, type, track, timestamp,
+        [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
+          using ::perfetto::internal::TrackEventLegacy;
+          ::perfetto::internal::LegacyTraceId trace_id{legacy_id};
+          TrackEventLegacy::WriteLegacyEventWithIdAndTid(
+              std::move(ctx), phase, flags, trace_id, thread_id, args...);
+        });
+  }
+#endif  // PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
+
   // Each category has its own enabled/disabled state, stored in the category
   // registry.
   struct CategoryTracePointTraits {
diff --git a/src/profiling/common/producer_support.h b/src/profiling/common/producer_support.h
index 6f54045..c1cd696 100644
--- a/src/profiling/common/producer_support.h
+++ b/src/profiling/common/producer_support.h
@@ -19,6 +19,7 @@
 
 #include <cinttypes>
 #include <string>
+#include <vector>
 
 #include "perfetto/tracing/core/forward_decls.h"
 
diff --git a/src/profiling/memory/unwinding.cc b/src/profiling/memory/unwinding.cc
index 3e03f5e..9263d0c 100644
--- a/src/profiling/memory/unwinding.cc
+++ b/src/profiling/memory/unwinding.cc
@@ -19,6 +19,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <condition_variable>
+#include <mutex>
+
 #include <unwindstack/MachineArm.h>
 #include <unwindstack/MachineArm64.h>
 #include <unwindstack/MachineMips.h>
diff --git a/src/protozero/protoc_plugin/protozero_plugin.cc b/src/protozero/protoc_plugin/protozero_plugin.cc
index bcfbf28..55c3c9d 100644
--- a/src/protozero/protoc_plugin/protozero_plugin.cc
+++ b/src/protozero/protoc_plugin/protozero_plugin.cc
@@ -874,8 +874,9 @@
 
       for (int j = 0; j < nested_enum->value_count(); ++j) {
         const EnumValueDescriptor* value = nested_enum->value(j);
-        stub_h_->Print("static const $class$ $name$ = $class$::$name$;\n",
-                       "class", nested_enum->name(), "name", value->name());
+        stub_h_->Print(
+            "static inline const $class$ $name$ = $class$::$name$;\n", "class",
+            nested_enum->name(), "name", value->name());
       }
     }
 
diff --git a/src/trace_processor/db/overlays/BUILD.gn b/src/trace_processor/db/overlays/BUILD.gn
index 6a0bf99..c1d50d8 100644
--- a/src/trace_processor/db/overlays/BUILD.gn
+++ b/src/trace_processor/db/overlays/BUILD.gn
@@ -13,7 +13,10 @@
 # limitations under the License.
 
 source_set("overlays") {
-  sources = [ "storage_overlay.h" ]
+  sources = [
+    "storage_overlay.h",
+    "types.h",
+  ]
   deps = [
     "../../../../gn:default_deps",
     "../../containers",
diff --git a/src/trace_processor/db/overlays/storage_overlay.h b/src/trace_processor/db/overlays/storage_overlay.h
index bee562e..58dbf50 100644
--- a/src/trace_processor/db/overlays/storage_overlay.h
+++ b/src/trace_processor/db/overlays/storage_overlay.h
@@ -17,10 +17,7 @@
 #ifndef SRC_TRACE_PROCESSOR_DB_OVERLAYS_STORAGE_OVERLAY_H_
 #define SRC_TRACE_PROCESSOR_DB_OVERLAYS_STORAGE_OVERLAY_H_
 
-#include <vector>
-
-#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/overlays/types.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -44,51 +41,9 @@
   // be in terms of storage indices and output might be in terms of table
   // indices).
   //
-  // For this reason, we define a bunch of wrapper structs which "tag" the data
+  // For this reason, we use the defined wrapper structs which "tag" the data
   // structure with the semantics.
 
-  // A range of indices in the table space.
-  struct TableRange {
-    RowMap::Range range;
-  };
-  // A range of indices in the storage space.
-  struct StorageRange {
-    RowMap::Range range;
-  };
-  // A BitVector with set bits corresponding to indices in the table space.
-  struct TableBitVector {
-    BitVector bv;
-  };
-  // A BitVector with set bits corresponding to indices in the table space.
-  struct StorageBitVector {
-    BitVector bv;
-  };
-  // Represents a vector of indices in the table space.
-  struct TableIndexVector {
-    std::vector<uint32_t> indices;
-  };
-  // Represents a vector of indices in the storage space.
-  struct StorageIndexVector {
-    std::vector<uint32_t> indices;
-  };
-
-  // A subset of FilterOp containing operations which can be handled by
-  // overlays.
-  enum class OverlayOp {
-    kIsNull,
-    kIsNotNull,
-    kOther,
-  };
-
-  // Contains estimates of the cost for each of method in this class per row.
-  struct CostEstimatePerRow {
-    uint32_t to_storage_range;
-    uint32_t to_table_bit_vector;
-    uint32_t is_storage_search_required;
-    uint32_t map_to_storage_index_vector;
-    uint32_t index_search;
-  };
-
   virtual ~StorageOverlay();
 
   // Maps a range of indices in table space to an equivalent range of
diff --git a/src/trace_processor/db/overlays/types.h b/src/trace_processor/db/overlays/types.h
new file mode 100644
index 0000000..4e72a41
--- /dev/null
+++ b/src/trace_processor/db/overlays/types.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SRC_TRACE_PROCESSOR_DB_OVERLAYS_TYPES_H_
+#define SRC_TRACE_PROCESSOR_DB_OVERLAYS_TYPES_H_
+
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/row_map.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace overlays {
+
+// A range of indices in the table space.
+struct TableRange {
+  RowMap::Range range;
+};
+
+// A range of indices in the storage space.
+struct StorageRange {
+  RowMap::Range range;
+};
+
+// A BitVector with set bits corresponding to indices in the table space.
+struct TableBitVector {
+  BitVector bv;
+};
+
+// A BitVector with set bits corresponding to indices in the table space.
+struct StorageBitVector {
+  BitVector bv;
+};
+
+// Represents a vector of indices in the table space.
+struct TableIndexVector {
+  std::vector<uint32_t> indices;
+};
+
+// Represents a vector of indices in the storage space.
+struct StorageIndexVector {
+  std::vector<uint32_t> indices;
+};
+
+// A subset of FilterOp containing operations which can be handled by
+// overlays.
+enum class OverlayOp {
+  kIsNull,
+  kIsNotNull,
+  kOther,
+};
+
+// Contains estimates of the cost for each of method in this class per row.
+struct CostEstimatePerRow {
+  uint32_t to_storage_range;
+  uint32_t to_table_bit_vector;
+  uint32_t is_storage_search_required;
+  uint32_t map_to_storage_index_vector;
+  uint32_t index_search;
+};
+
+}  // namespace overlays
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_DB_OVERLAYS_TYPES_H_
diff --git a/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql b/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql
index 3538f7d..0724ba7 100644
--- a/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql
+++ b/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql
@@ -126,6 +126,8 @@
             OR s.name GLOB '*CancellableContinuationImpl*'
             OR s.name GLOB 'relayoutWindow*'
             OR s.name GLOB 'ImageDecoder#decode*'
+            OR s.name GLOB 'NotificationStackScrollLayout#onMeasure'
+            OR s.name GLOB 'ExpNotRow#*'
         )
     UNION ALL
     SELECT
diff --git a/src/trace_processor/metrics/sql/chrome/chrome_scroll_jank_v2.sql b/src/trace_processor/metrics/sql/chrome/chrome_scroll_jank_v2.sql
index 9461d2c..47f1876 100644
--- a/src/trace_processor/metrics/sql/chrome/chrome_scroll_jank_v2.sql
+++ b/src/trace_processor/metrics/sql/chrome/chrome_scroll_jank_v2.sql
@@ -18,6 +18,37 @@
 
 SELECT RUN_METRIC('chrome/event_latency_scroll_jank_cause.sql');
 
+DROP VIEW IF EXISTS chrome_scroll_jank_v2;
+
+CREATE VIEW chrome_scroll_jank_v2
+AS
+SELECT
+  100.0 * scroll_jank_processing_ms / scroll_processing_ms
+    AS scroll_jank_percentage,
+  *
+FROM
+  (
+    SELECT
+      COALESCE(SUM(jank.dur), 0) / 1.0e6 AS scroll_processing_ms,
+      COALESCE(
+        SUM(
+          CASE
+            WHEN
+              jank.jank
+              AND cause.cause_of_jank != 'RendererCompositorQueueingDelay'
+              THEN jank.dur
+            ELSE 0
+            END),
+        0)
+        / 1.0e6 AS scroll_jank_processing_ms
+    FROM
+      scroll_event_latency_jank AS jank
+    LEFT JOIN
+      event_latency_scroll_jank_cause AS cause
+      ON
+        jank.id = cause.slice_id
+  );
+
 DROP VIEW IF EXISTS chrome_scroll_jank_v2_output;
 
 CREATE VIEW chrome_scroll_jank_v2_output
@@ -31,31 +62,4 @@
     'scroll_jank_percentage',
     scroll_jank_percentage)
 FROM
-  (
-    SELECT
-      100.0 * scroll_jank_processing_ms / scroll_processing_ms
-        AS scroll_jank_percentage,
-      *
-    FROM
-      (
-        SELECT
-          COALESCE(SUM(jank.dur), 0) / 1.0e6 AS scroll_processing_ms,
-          COALESCE(
-            SUM(
-              CASE
-                WHEN
-                  jank.jank
-                  AND cause.cause_of_jank != 'RendererCompositorQueueingDelay'
-                  THEN jank.dur
-                ELSE 0
-                END),
-            0)
-            / 1.0e6 AS scroll_jank_processing_ms
-        FROM
-          scroll_event_latency_jank AS jank
-        LEFT JOIN
-          event_latency_scroll_jank_cause AS cause
-          ON
-            jank.id = cause.slice_id
-      )
-  );
+  chrome_scroll_jank_v2;
diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc
index 0755e02..7fdc70c 100644
--- a/src/tracing/test/api_integrationtest.cc
+++ b/src/tracing/test/api_integrationtest.cc
@@ -3472,7 +3472,8 @@
       "foo", perfetto::DynamicString{std::string("Event5")},
       ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END);
   PERFETTO_INTERNAL_TRACK_EVENT(
-      "foo", "Event6", ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END);
+      "foo", perfetto::StaticString{"Event6"},
+      ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END);
 
   auto slices = StopSessionAndReadSlicesFromTrace(tracing_session);
   ASSERT_EQ(6u, slices.size());
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
index adfa483..71dc5bf 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
@@ -1 +1 @@
-37ce86e92a72fe05c24acfcadf1393f3407a99e3dcdda6b3c883f380ffd00b41
\ No newline at end of file
+24a0c7c0bd17908474dda832f51aca06226c44f93043b6b6ff8b698d013818ea
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
index ba42f34..2e2f6fd 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
@@ -1 +1 @@
-0c7f3705f1d29c0b16756b66cb748635352fef3928a173b34d995356e6d3d58e
\ No newline at end of file
+01576322a83634df3f5d4fee6c7dac5c3835f926b7de752b99e827e5688fec2d
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
index 4c65000..58c3975 100644
--- a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
@@ -1 +1 @@
-c8277a777519e7c1bf762d4e0e299a79a66da88ce54ed26e6d27939dca6128c9
\ No newline at end of file
+f618d3e05c466f49a4e130b02b1ab597dc8e0d51285c801fa9af3c6e9df505a5
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
index f504faf..9d7b91c 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
@@ -1 +1 @@
-dc246b0bf68834a63464c0c98e35a060cb3698947084cdb9d976207a37bf8156
\ No newline at end of file
+86d0bc258ef11ba82a78f4b28a1463fb4b732545b95f2ee8e8a4d6271370a030
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
index 0ee6b17..312b01f 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
@@ -1 +1 @@
-e79c53f02bed0a629c76fd3d044492dc8e619fe9f58c597db5f4417cbe91f805
\ No newline at end of file
+c8e073f0030da0c6d2dd514eed99a8e0eed79ec75c18e177812de73bf0440cf2
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
index 0e50d9b..0332663 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
@@ -1 +1 @@
-cc543d6db95f56863f5d6c90dbbb8b07e8dff539534c53d595b1faee807903da
\ No newline at end of file
+b841b628cd3908f434d28ad0234656ceaeb4a418659200e2670343d2f885fa68
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
index bf8f89b..69e55e1 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
@@ -1 +1 @@
-db689629c3ba9a51e74d48edd3e801bf062dd985ed5210e5a9b4f1bce50f29a7
\ No newline at end of file
+e7dc92a76eec326637bebaa176482197c621f48bc066fc761d0b1d19513c8c21
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
index 6c30778..67a8dd4 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
@@ -1 +1 @@
-eae8d6c700a16b5062736c54e4fe0ffab569ffd839715138e74cd257fdb014fa
\ No newline at end of file
+2d66039e67f93ea58155d19d3be5aba40d3d6f0053f9d1ada63e47828af28abe
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
index 5117a65..623260e 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
@@ -1 +1 @@
-5767e81834101bf14dcd1917544f1605b8dbb8aa747a7eefd1c52f4db891575f
\ No newline at end of file
+b51e0a5035eab217bc4339800e8a6c4025bfc7d5240844c152fbc867b28f75ba
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
index ff3aafa..679bd39 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
@@ -1 +1 @@
-ab1a1b7c948e008fa5d44a4471dc24977f3ab2d592c1ceeaa0ab4afac5bb2336
\ No newline at end of file
+99d3e463fe3812942825829a388bb2d5b11d73010c3213b11d09884dfc1663b5
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
index f4e56d2..21fefdd 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
@@ -1 +1 @@
-d7c89c766d8db408de06f79654e2f81d8c761c08c4451991447807468df0f3d5
\ No newline at end of file
+a151d536d2061b45910d894b1735ddc4eac97c4102754d7f1e1b31ebde368675
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
index 46f0129..849be2d 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
@@ -1 +1 @@
-e596f8037a578f1e58a33bbe08f5d5621b1d37e55456409e5f8799a6897eedb9
\ No newline at end of file
+4b07a28b92a72568615003beb4eb086adc9be581a27baa2ea593c5e88802647b
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
index 23be44d..8e93988 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
@@ -1 +1 @@
-b938d4dfcc109165feaedb9421276a355d03a383a0d21ab91ff72409b18a3ab5
\ No newline at end of file
+56ec21cedc480d6b1b2a894bc70411c89424386a7910d62a09a6a5f1a5921c15
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
index b3b1619..df63f69 100644
--- a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
@@ -1 +1 @@
-ae78e1f372a6a052a650974464f2e706ab8cb665c639ca4b0b15b48dce95d185
\ No newline at end of file
+10931936be5a35ed461fce47ede47225ffc750a85a13462a614366f26160ca11
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
index 0abbaa7..2afc1a3 100644
--- a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
@@ -1 +1 @@
-d62fb2e2f4067552d4f9d4170b4ffa45c74171b4de750292ded957cb6b12b669
\ No newline at end of file
+04e0762424dae233fb13d5cfff51a2d3075ad62220538010d0ab376fc79022a9
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
index 9287876..6272735 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
@@ -1 +1 @@
-30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6
\ No newline at end of file
+c421aafc09b9ce506fd6eaa1dc358855182cd18704715491f83b7d49828c5826
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
index 23be44d..8e93988 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
@@ -1 +1 @@
-b938d4dfcc109165feaedb9421276a355d03a383a0d21ab91ff72409b18a3ab5
\ No newline at end of file
+56ec21cedc480d6b1b2a894bc70411c89424386a7910d62a09a6a5f1a5921c15
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
index 9287876..6272735 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
@@ -1 +1 @@
-30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6
\ No newline at end of file
+c421aafc09b9ce506fd6eaa1dc358855182cd18704715491f83b7d49828c5826
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
index 9287876..6272735 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
@@ -1 +1 @@
-30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6
\ No newline at end of file
+c421aafc09b9ce506fd6eaa1dc358855182cd18704715491f83b7d49828c5826
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
index 4324721..a494f13 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
@@ -1 +1 @@
-9d502e8458f85884c7bf1a6411aa3425c63ccf102e6f537318733704e7a416fb
\ No newline at end of file
+8de36401497e509ab127d202b83a056c40c2f5f461254f1ea79fe7a4861b059e
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
index 535b9b1..cbb5609 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
@@ -1 +1 @@
-b0d5928fbcf0b7adfc06386ea1961d301ee19f66c61b190f9d00fd5acef824c0
\ No newline at end of file
+7b0fb778fef603ab28c5bc8459db420d2c9d6c6a7a3e5b4e6547b3a2fb067249
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
index 23be44d..8e93988 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
@@ -1 +1 @@
-b938d4dfcc109165feaedb9421276a355d03a383a0d21ab91ff72409b18a3ab5
\ No newline at end of file
+56ec21cedc480d6b1b2a894bc70411c89424386a7910d62a09a6a5f1a5921c15
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
index 9287876..6272735 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
@@ -1 +1 @@
-30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6
\ No newline at end of file
+c421aafc09b9ce506fd6eaa1dc358855182cd18704715491f83b7d49828c5826
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
index 9287876..6272735 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
@@ -1 +1 @@
-30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6
\ No newline at end of file
+c421aafc09b9ce506fd6eaa1dc358855182cd18704715491f83b7d49828c5826
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out
index d75d44d..c4e2b2b 100644
--- a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out
+++ b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out
@@ -44,7 +44,7 @@
       pid: 3000
     }
     ts: 2000000
-    dur: 150000000
+    dur: 180000000
     blocking_calls {
       name: "Contending for pthread mutex"
       cnt: 1
@@ -60,6 +60,20 @@
       min_dur_ms: 10
     }
     blocking_calls {
+      name: "ExpNotRow#onMeasure(BigTextStyle)"
+      cnt: 1
+      total_dur_ms: 10
+      max_dur_ms: 10
+      min_dur_ms: 10
+    }
+    blocking_calls {
+      name: "ExpNotRow#onMeasure(MessagingStyle)"
+      cnt: 1
+      total_dur_ms: 10
+      max_dur_ms: 10
+      min_dur_ms: 10
+    }
+    blocking_calls {
       name: "ImageDecoder#decodeBitmap"
       cnt: 1
       total_dur_ms: 10
@@ -88,6 +102,13 @@
       min_dur_ms: 10
     }
     blocking_calls {
+      name: "NotificationStackScrollLayout#onMeasure"
+      cnt: 1
+      total_dur_ms: 10
+      max_dur_ms: 10
+      min_dur_ms: 10
+    }
+    blocking_calls {
       name: "SuspendThreadByThreadId <...>"
       cnt: 1
       total_dur_ms: 10
diff --git a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py
index 1039e47..528f494 100755
--- a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py
+++ b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py
@@ -31,6 +31,8 @@
     'CancellableContinuationImpl#123', 'relayoutWindow*', 'measure', 'layout',
     'configChanged', 'Contending for pthread mutex',
     'ImageDecoder#decodeBitmap', 'ImageDecoder#decodeDrawable',
+    'NotificationStackScrollLayout#onMeasure', 'ExpNotRow#onMeasure(MessagingStyle)',
+    'ExpNotRow#onMeasure(BigTextStyle)',
     'Should not be in the metric'
 ]
 
diff --git a/test/trace_processor/diff_tests/chrome/chrome_scroll_jank_v2.out b/test/trace_processor/diff_tests/chrome/chrome_scroll_jank_v2.out
index dae2c44..b13137f 100644
--- a/test/trace_processor/diff_tests/chrome/chrome_scroll_jank_v2.out
+++ b/test/trace_processor/diff_tests/chrome/chrome_scroll_jank_v2.out
@@ -1,4 +1,3 @@
 
 "scroll_processing_ms","scroll_jank_processing_ms","scroll_jank_percentage"
 12374.560000,154.217000,1.246242
-
diff --git a/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py b/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
index c8594d1..ef0f373 100644
--- a/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
+++ b/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
@@ -541,17 +541,16 @@
         5680,120000000,70000000,120000000,-1
         """))
 
-  # TODO(283531332): reenable this test after fixing.
-  # def test_chrome_scroll_jank_v2(self):
-  #   return DiffTestBlueprint(
-  #       trace=Path('../../data/event_latency_with_args.perfetto-trace'),
-  #       query="""
-  #       SELECT RUN_METRIC('chrome/chrome_scroll_jank_v2.sql');
+  def test_chrome_scroll_jank_v2(self):
+    return DiffTestBlueprint(
+        trace=DataPath('event_latency_with_args.perfetto-trace'),
+        query="""
+        SELECT RUN_METRIC('chrome/chrome_scroll_jank_v2.sql');
 
-  #       SELECT
-  #         scroll_processing_ms,
-  #         scroll_jank_processing_ms,
-  #         scroll_jank_percentage
-  #       FROM chrome_scroll_jank_v2_output;
-  #       """,
-  #       out=Path('chrome_scroll_jank_v2.out'))
+        SELECT
+          scroll_processing_ms,
+          scroll_jank_processing_ms,
+          scroll_jank_percentage
+        FROM chrome_scroll_jank_v2;
+        """,
+        out=Path('chrome_scroll_jank_v2.out'))
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 179ac14..b154ee3 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -103,6 +103,7 @@
     '//protos/perfetto/trace:perfetto_trace_protos',
     '//src/trace_processor:demangle',
     '//src/trace_processor:trace_processor_shell',
+    '//src/traced/probes:traced_probes',
     '//src/traced/service:traced',
 ]
 
diff --git a/ui/src/assets/common.scss b/ui/src/assets/common.scss
index 0435422..c26ee4f 100644
--- a/ui/src/assets/common.scss
+++ b/ui/src/assets/common.scss
@@ -187,10 +187,6 @@
   }
 }
 
-.query-table-container {
-  width: 100%;
-}
-
 @mixin table-font-size {
   font-size: 14px;
   line-height: 18px;
@@ -270,8 +266,9 @@
   font-size: 14px;
   border: 0;
   thead td {
-    position: sticky;
-    top: 0;
+    // TODO(stevegolton): Get sticky working again.
+    // position: sticky;
+    // top: 0;
     background-color: hsl(214, 22%, 90%);
     color: #262f3c;
     text-align: center;
@@ -471,17 +468,7 @@
 
 .details-panel-container {
   box-shadow: #0000003b 0px 0px 3px 1px;
-  position: relative;
-  overflow-x: hidden;
-  overflow-y: auto;
-  flex: 1 1 auto;
-  // TODO(hjd): This causes the sticky header to flicker when scrolling.
-  // Is will-change necessary in the details panel?
-  // will-change: transform;
-  display: grid;
-  grid-template-columns: 1fr;
-  grid-template-rows: 1fr;
-  grid-template-areas: "space";
+  overflow: auto;
 }
 
 .pinned-panel-container {
@@ -520,9 +507,10 @@
   position: relative; // Otherwise canvas covers panel dom.
 
   &.sticky {
-    position: sticky;
+    // TODO(stevegolton): Get sticky working again.
+    // position: sticky;
     z-index: 3;
-    top: 0;
+    // top: 0;
     background-color: hsl(215, 22%, 19%);
   }
 }
@@ -555,6 +543,9 @@
 }
 
 header.overview {
+  position: sticky;
+  top: 0;
+  left: 0;
   display: flex;
   align-content: baseline;
   background-color: hsl(213, 22%, 82%);
diff --git a/ui/src/assets/details.scss b/ui/src/assets/details.scss
index b5c131b..50e0d20 100644
--- a/ui/src/assets/details.scss
+++ b/ui/src/assets/details.scss
@@ -12,92 +12,87 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-.details-content {
+.handle {
+  background-color: hsl(215, 1%, 95%);
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  border-bottom: none;
+  cursor: row-resize;
+  // Disable user selection since this handle is draggable to resize the
+  // bottom panels.
+  user-select: none;
+  height: 28px;
+  min-height: 28px;
   display: grid;
-  grid-template-rows: auto 1fr;
+  grid-auto-columns: 1fr 60px;
+  grid-template-areas: "tabs buttons";
 
-  .handle {
-    background-color: hsl(215, 1%, 95%);
-    border: 1px solid rgba(0, 0, 0, 0.1);
-    border-bottom: none;
-    cursor: row-resize;
-    // Disable user selection since this handle is draggable to resize the
-    // bottom panels.
-    user-select: none;
-    height: 28px;
-    min-height: 28px;
-    display: grid;
-    grid-auto-columns: 1fr 60px;
-    grid-template-areas: "tabs buttons";
+  .tabs {
+    display: flex;
+    grid-area: tabs;
+    overflow: hidden;
 
-    .tabs {
-      display: flex;
-      grid-area: tabs;
+    .tab {
+      font-family: "Roboto Condensed", sans-serif;
+      color: #3c4b5d;
+      padding: 3px 10px 0 10px;
+      margin-top: 3px;
+      font-size: 13px;
+      border-radius: 3px 3px 0 0;
+      background-color: #0000000f;
+      border-right: solid 1px hsla(0, 0%, 75%, 1);
       overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      z-index: 5;
+      box-shadow: #0000003b 0px 0px 3px 1px;
 
-      .tab {
-        font-family: "Roboto Condensed", sans-serif;
-        color: #3c4b5d;
-        padding: 3px 10px 0 10px;
-        margin-top: 3px;
-        font-size: 13px;
-        border-radius: 3px 3px 0 0;
-        background-color: #0000000f;
-        border-right: solid 1px hsla(0, 0%, 75%, 1);
-        overflow: hidden;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-        z-index: 5;
-        box-shadow: #0000003b 0px 0px 3px 1px;
-
-        &[active] {
-          background-color: white;
-          &:hover {
-            cursor: default;
-            background-color: white;
-          }
-        }
-
-        &:hover {
-          cursor: pointer;
-          background-color: hsla(0, 0%, 85%, 1);
-        }
-
-        &:nth-child(1) {
-          margin-left: 3px;
-        }
-      }
-    }
-
-    i.material-icons {
-      font-size: 24px;
-      margin-right: 5px;
-      margin-top: 1px;
-      &:hover {
-        cursor: pointer;
-      }
-      &[disabled] {
-        color: rgb(219, 219, 219);
+      &[active] {
+        background-color: white;
         &:hover {
           cursor: default;
+          background-color: white;
         }
       }
-    }
 
-    .buttons {
-      grid-area: buttons;
-      text-align: right;
-    }
+      &:hover {
+        cursor: pointer;
+        background-color: hsla(0, 0%, 85%, 1);
+      }
 
-    .handle-title {
-      font-family: "Roboto Condensed", sans-serif;
-      font-weight: 300;
-      color: #3c4b5d;
-      margin-left: 5px;
-      padding: 5px;
-      font-size: 13px;
+      &:nth-child(1) {
+        margin-left: 3px;
+      }
     }
   }
+
+  i.material-icons {
+    font-size: 24px;
+    margin-right: 5px;
+    margin-top: 1px;
+    &:hover {
+      cursor: pointer;
+    }
+    &[disabled] {
+      color: rgb(219, 219, 219);
+      &:hover {
+        cursor: default;
+      }
+    }
+  }
+
+  .buttons {
+    grid-area: buttons;
+    text-align: right;
+  }
+
+  .handle-title {
+    font-family: "Roboto Condensed", sans-serif;
+    font-weight: 300;
+    color: #3c4b5d;
+    margin-left: 5px;
+    padding: 5px;
+    font-size: 13px;
+  }
 }
 
 .details-panel {
@@ -402,16 +397,12 @@
 }
 
 .log-panel {
-  width: 100%;
-  height: 100%;
-  display: grid;
-  grid-template-rows: auto 1fr;
-  font-family: "Roboto Condensed", sans-serif;
-  user-select: text;
+  display: contents;
 
   header {
     position: sticky;
     top: 0;
+    left: 0;
     z-index: 1;
     background-color: white;
     color: #3c4b5d;
@@ -620,14 +611,12 @@
 }
 
 .ftrace-panel {
-  display: grid;
-  grid-template-rows: auto 1fr;
-  font-family: "Roboto Condensed", sans-serif;
-  user-select: text;
+  display: contents;
 
   .sticky {
     position: sticky;
     top: 0;
+    left: 0;
     z-index: 1;
     background-color: white;
     color: #3c4b5d;
diff --git a/ui/src/frontend/details_panel.ts b/ui/src/frontend/details_panel.ts
index e3a7585..ad04665 100644
--- a/ui/src/frontend/details_panel.ts
+++ b/ui/src/frontend/details_panel.ts
@@ -39,7 +39,7 @@
 import {globals} from './globals';
 import {LogPanel} from './logs_panel';
 import {NotesEditorTab} from './notes_panel';
-import {AnyAttrsVnode, PanelContainer} from './panel_container';
+import {AnyAttrsVnode} from './panel_container';
 import {PivotTable} from './pivot_table';
 import {SliceDetailsPanel} from './slice_details_panel';
 import {ThreadStateTab} from './thread_state_tab';
@@ -152,7 +152,7 @@
               onclick: () => {
                 this.isClosed = false;
                 this.isFullscreen = true;
-                this.resize(this.fullscreenHeight);
+                this.resize(this.fullscreenHeight - DRAG_HANDLE_HEIGHT_PX);
                 globals.rafScheduler.scheduleFullRedraw();
               },
               title: 'Open fullscreen',
@@ -172,7 +172,7 @@
                   this.isFullscreen = false;
                   this.isClosed = true;
                   this.previousHeight = this.height;
-                  this.resize(DRAG_HANDLE_HEIGHT_PX);
+                  this.resize(0);
                 }
                 globals.rafScheduler.scheduleFullRedraw();
               },
@@ -390,27 +390,27 @@
     }
 
     const panel = currentTabDetails?.vnode;
-    const panels = panel ? [panel] : [];
 
-    return m(
-        '.details-content',
-        {
-          style: {
-            height: `${this.detailsHeight}px`,
-            display: detailsPanels.length > 0 ? null : 'none',
-          },
+    if (!panel) {
+      return null;
+    }
+
+    return [
+      m(DragHandle, {
+        resize: (height: number) => {
+          this.detailsHeight = Math.max(height, 0);
         },
-        m(DragHandle, {
-          resize: (height: number) => {
-            this.detailsHeight = Math.max(height, DRAG_HANDLE_HEIGHT_PX);
-          },
-          height: this.detailsHeight,
-          tabs: detailsPanels.map((tab) => {
-            return {key: tab.key, name: tab.name};
-          }),
-          currentTabKey: currentTabDetails?.key,
+        height: this.detailsHeight,
+        tabs: detailsPanels.map((tab) => {
+          return {key: tab.key, name: tab.name};
         }),
-        m('.details-panel-container.x-scrollable',
-          m(PanelContainer, {doesScroll: true, panels, kind: 'DETAILS'})));
+        currentTabKey: currentTabDetails?.key,
+      }),
+      m('.details-panel-container',
+        {
+          style: {height: `${this.detailsHeight}px`},
+        },
+        panel),
+    ];
   }
 }
diff --git a/ui/src/frontend/ftrace_panel.ts b/ui/src/frontend/ftrace_panel.ts
index e45b5fe..f66cddf 100644
--- a/ui/src/frontend/ftrace_panel.ts
+++ b/ui/src/frontend/ftrace_panel.ts
@@ -68,7 +68,7 @@
   }
 
   private scrollContainer(dom: Element): HTMLElement {
-    const el = dom.parentElement!.parentElement!.parentElement;
+    const el = dom.parentElement;
     return assertExists(el);
   }
 
diff --git a/ui/src/frontend/logs_panel.ts b/ui/src/frontend/logs_panel.ts
index 88baa1c..8c50589 100644
--- a/ui/src/frontend/logs_panel.ts
+++ b/ui/src/frontend/logs_panel.ts
@@ -58,8 +58,7 @@
   }
 
   oncreate({dom}: m.CVnodeDOM) {
-    this.scrollContainer = assertExists(
-        dom.parentElement!.parentElement!.parentElement as HTMLElement);
+    this.scrollContainer = assertExists(dom.parentElement as HTMLElement);
     this.scrollContainer.addEventListener(
         'scroll', this.onScroll.bind(this), {passive: true});
     // TODO(stevegolton): Type assersions are a source of bugs.
diff --git a/ui/src/frontend/query_table.ts b/ui/src/frontend/query_table.ts
index a77c0ef..be864fc 100644
--- a/ui/src/frontend/query_table.ts
+++ b/ui/src/frontend/query_table.ts
@@ -183,9 +183,7 @@
     if (resp.error) {
       return m('.query-error', `SQL error: ${resp.error}`);
     } else {
-      return m(
-          '.query-table-container.x-scrollable',
-          m('table.query-table', m('thead', tableHeader), m('tbody', rows)));
+      return m('table.query-table', m('thead', tableHeader), m('tbody', rows));
     }
   }
 }
@@ -236,7 +234,7 @@
     const headers = [m('header.overview', ...header)];
 
     if (resp === undefined) {
-      return m('div', ...headers);
+      return headers;
     }
 
     if (resp.statementWithOutputCount > 1) {
@@ -247,7 +245,7 @@
                 `statement are displayed in the table below.`));
     }
 
-    return m('div', ...headers, m(QueryTableContent, {resp}));
+    return [...headers, m(QueryTableContent, {resp})];
   }
 
   renderCanvas() {}
diff --git a/ui/src/frontend/track_cache.ts b/ui/src/frontend/track_cache.ts
index b4178aa..61f17b1 100644
--- a/ui/src/frontend/track_cache.ts
+++ b/ui/src/frontend/track_cache.ts
@@ -63,8 +63,8 @@
 
   static create(startNs: TPTime, endNs: TPTime, windowSizePx: number):
       CacheKey {
-    const bucketNs =
-        (endNs - startNs) / BigInt(windowSizePx * BUCKETS_PER_PIXEL);
+    const bucketNs = (endNs - startNs) /
+        BigInt(Math.round(windowSizePx * BUCKETS_PER_PIXEL));
     return new CacheKey(startNs, endNs, bucketNs, windowSizePx);
   }