Merge "Use python3 for profiling scripts."
diff --git a/.gn b/.gn
index 692a951..d7ecabe 100644
--- a/.gn
+++ b/.gn
@@ -13,3 +13,4 @@
 # limitations under the License.
 
 buildconfig = "//gn/standalone/BUILDCONFIG.gn"
+script_executable = "python3"
diff --git a/BUILD b/BUILD
index 83099f4..f61f3d7 100644
--- a/BUILD
+++ b/BUILD
@@ -3564,7 +3564,6 @@
         ":src_profiling_deobfuscator",
         ":src_profiling_symbolizer_symbolize_database",
         ":src_profiling_symbolizer_symbolizer",
-        ":src_trace_processor_containers_containers",
         ":tools_trace_to_text_pprofbuilder",
         ":tools_trace_to_text_utils",
     ],
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index a59c492..98022c9 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -1058,6 +1058,7 @@
   visibility = _buildtools_visibility
   cflags = [
     "-DJSON_USE_EXCEPTION=0",
+    "-Wno-deprecated-declarations",
 
     # Using -isystem instead of include_dirs (-I), so we don't need to suppress
     # warnings coming from third-party headers. Doing so would mask warnings in
diff --git a/debian/control b/debian/control
index be52af4..d8cd8ea 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,7 @@
 Section: kernel
 Priority: optional
 Maintainer: Sami Kyostila <skyostil@google.com>
-Build-Depends: debhelper (>= 10)
+Build-Depends: debhelper (>= 10), python3, git
 Standards-Version: 3.9.8
 Homepage: https://perfetto.dev
 Vcs-Git: https://android.googlesource.com/platform/external/perfetto/
diff --git a/gn/write_buildflag_header.py b/gn/write_buildflag_header.py
index 8045cce..617ab7d 100644
--- a/gn/write_buildflag_header.py
+++ b/gn/write_buildflag_header.py
@@ -67,7 +67,7 @@
   guard = '%s_' % args.out.upper()
   guard = guard.replace('/', '_').replace('\\', '_').replace('.', '_')
   lines = []
-  lines.append('// Generated by %s' % __file__)
+  lines.append('// Generated by %s' % os.path.basename(__file__))
   lines.append('')
   lines.append('// fix_include_guards: off')
   lines.append('#ifndef %s' % guard)
diff --git a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
index 7a34606..f0179c6 100644
--- a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-// Generated by ../../gn/write_buildflag_header.py
+// Generated by write_buildflag_header.py
 
 // fix_include_guards: off
 #ifndef GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
index ada8006..6745b3f 100644
--- a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-// Generated by ../../gn/write_buildflag_header.py
+// Generated by write_buildflag_header.py
 
 // fix_include_guards: off
 #ifndef GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/profiling/pprof_builder.h b/include/perfetto/profiling/pprof_builder.h
index df18c5a..20b9d2e 100644
--- a/include/perfetto/profiling/pprof_builder.h
+++ b/include/perfetto/profiling/pprof_builder.h
@@ -17,6 +17,7 @@
 #ifndef INCLUDE_PERFETTO_PROFILING_PPROF_BUILDER_H_
 #define INCLUDE_PERFETTO_PROFILING_PPROF_BUILDER_H_
 
+#include <iostream>
 #include <string>
 #include <vector>
 
@@ -47,19 +48,9 @@
 
 enum class ConversionMode { kHeapProfile, kPerfProfile };
 
-enum class ConversionFlags : uint64_t {
-  kNone = 0,
-  // Suffix frame names with additional information. Current annotations are
-  // specific to apps running within the Android runtime, and include
-  // information such as whether the given frame was interpreted / executed
-  // under JIT / etc.
-  kAnnotateFrames = 1
-};
-
 bool TraceToPprof(trace_processor::TraceProcessor* tp,
                   std::vector<SerializedProfile>* output,
                   ConversionMode mode = ConversionMode::kHeapProfile,
-                  uint64_t flags = 0,
                   uint64_t pid = 0,
                   const std::vector<uint64_t>& timestamps = {});
 
diff --git a/include/perfetto/protozero/proto_utils.h b/include/perfetto/protozero/proto_utils.h
index bb2e5ce..841042b 100644
--- a/include/perfetto/protozero/proto_utils.h
+++ b/include/perfetto/protozero/proto_utils.h
@@ -276,6 +276,21 @@
   using message_type = MessageType;
 };
 
+namespace internal {
+
+// Ideally we would create variables of FieldMetadata<...> type directly,
+// but before C++17's support for constexpr inline variables arrive, we have to
+// actually use pointers to inline functions instead to avoid having to define
+// symbols in *.pbzero.cc files.
+//
+// Note: protozero bindings will generate Message::kFieldName variable and which
+// can then be passed to TRACE_EVENT macro for inline writing of typed messages.
+// The fact that the former can be passed to the latter is a part of the stable
+// API, while the particular type is not and users should not rely on it.
+template <typename T>
+using FieldMetadataHelper = T (*)(void);
+
+}  // namespace internal
 }  // namespace proto_utils
 }  // namespace protozero
 
diff --git a/include/perfetto/tracing/internal/write_track_event_args.h b/include/perfetto/tracing/internal/write_track_event_args.h
index 8263110..9a68ab5 100644
--- a/include/perfetto/tracing/internal/write_track_event_args.h
+++ b/include/perfetto/tracing/internal/write_track_event_args.h
@@ -100,7 +100,8 @@
                               FieldMetadataType>::value>>
 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(
     EventContext event_ctx,
-    const FieldMetadataType& field_name,
+    protozero::proto_utils::internal::FieldMetadataHelper<FieldMetadataType>
+        field_name,
     ArgValue&& arg_value,
     Args&&... args) {
   static_assert(
diff --git a/include/perfetto/tracing/traced_proto.h b/include/perfetto/tracing/traced_proto.h
index d88dbc1..88ee99e 100644
--- a/include/perfetto/tracing/traced_proto.h
+++ b/include/perfetto/tracing/traced_proto.h
@@ -166,9 +166,10 @@
 }  // namespace internal
 
 template <typename MessageType, typename FieldMetadataType, typename ValueType>
-void WriteIntoTracedProto(TracedProto<MessageType> message,
-                          const FieldMetadataType&,
-                          ValueType&& value) {
+void WriteIntoTracedProto(
+    TracedProto<MessageType> message,
+    protozero::proto_utils::internal::FieldMetadataHelper<FieldMetadataType>,
+    ValueType&& value) {
   static_assert(
       std::is_base_of<protozero::proto_utils::FieldMetadataBase,
                       FieldMetadataType>::value,
diff --git a/infra/ci/config.py b/infra/ci/config.py
index f35178e..be325ab 100755
--- a/infra/ci/config.py
+++ b/infra/ci/config.py
@@ -145,6 +145,7 @@
 
   if len(sys.argv) > 1 and sys.argv[1] == 'js':
     jsn = json.dumps(vars, indent=2)
-    print('// Auto-generated by %s, do not edit.\n' % __file__)
+    print('// Auto-generated by %s, do not edit.\n' %
+          os.path.basename(__file__))
     print('\'use strict\';\n')
     print('const cfg = JSON.parse(`%s`);\n' % jsn.replace(r'\"', r'\\\"'))
diff --git a/infra/perfetto.dev/build.js b/infra/perfetto.dev/build.js
index 086234d..1fc657c 100644
--- a/infra/perfetto.dev/build.js
+++ b/infra/perfetto.dev/build.js
@@ -73,7 +73,11 @@
 
   // Check that deps are current before starting.
   const installBuildDeps = pjoin(ROOT_DIR, 'tools/install-build-deps');
-  const depsArgs = ['--check-only', '/dev/null', '--ui'];
+
+  // --filter=nodejs is to match what cloud_build_entrypoint.sh passes to
+  // install-build-deps. It doesn't bother installing the full toolchains
+  // because, unlike the Perfetto UI, it doesn't need Wasm.
+  const depsArgs = ['--check-only=/dev/null', '--ui', '--filter=nodejs'];
   exec(installBuildDeps, depsArgs);
 
   console.log('Entering', cfg.outDir);
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 84d9af3..c76e064 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -926,6 +926,9 @@
   }
 
   if (save_to_incidentd_) {
+    if (!uuid_.empty()) {
+      PERFETTO_LOG("go/trace-uuid/%s", uuid_.c_str());
+    }
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
     SaveTraceIntoDropboxAndIncidentOrCrash();
 #endif
diff --git a/src/profiling/common/producer_support.cc b/src/profiling/common/producer_support.cc
index d6a58ec..fc92714 100644
--- a/src/profiling/common/producer_support.cc
+++ b/src/profiling/common/producer_support.cc
@@ -61,10 +61,6 @@
     return true;
   }
 
-  if (ds_config.enable_extra_guardrails()) {
-    return false;  // no extra guardrails on user builds.
-  }
-
   uint64_t uid_without_profile = uid % kAidUserOffset;
   if (uid_without_profile < kAidAppStart || kAidAppEnd < uid_without_profile) {
     // TODO(fmayer): relax this.
@@ -82,9 +78,14 @@
       PERFETTO_ELOG("Failed to parse packages.list.");
       return false;
     }
-    if (pkg.uid == uid_without_profile &&
-        (pkg.profileable_from_shell || pkg.debuggable)) {
-      return true;
+    if (pkg.uid == uid_without_profile) {
+      if (pkg.profileable) {
+        return true;
+      }
+      if (!ds_config.enable_extra_guardrails() &&
+          (pkg.profileable_from_shell || pkg.debuggable)) {
+        return true;
+      }
     }
   }
   return false;
diff --git a/src/profiling/common/producer_support_unittest.cc b/src/profiling/common/producer_support_unittest.cc
index df2129a..4b94e89 100644
--- a/src/profiling/common/producer_support_unittest.cc
+++ b/src/profiling/common/producer_support_unittest.cc
@@ -32,7 +32,7 @@
   EXPECT_TRUE(CanProfileAndroid(ds_config, 1, "userdebug", "/dev/null"));
 }
 
-TEST(CanProfileAndroidTest, NonUserNonProfileableApp) {
+TEST(CanProfileAndroidTest, NonUserNonProfileableByShellApp) {
   DataSourceConfig ds_config;
   ds_config.set_enable_extra_guardrails(false);
   auto tmp = base::TempFile::Create();
@@ -44,7 +44,7 @@
   EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "userdebug", tmp.path()));
 }
 
-TEST(CanProfileAndroidTest, NonUserNonProfileableAppExtraGuardrails) {
+TEST(CanProfileAndroidTest, NonUserNonProfileableByShellAppExtraGuardrails) {
   DataSourceConfig ds_config;
   ds_config.set_enable_extra_guardrails(true);
   auto tmp = base::TempFile::Create();
@@ -56,7 +56,7 @@
   EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "userdebug", tmp.path()));
 }
 
-TEST(CanProfileAndroidTest, UserProfileableApp) {
+TEST(CanProfileAndroidTest, UserProfileableByShellApp) {
   DataSourceConfig ds_config;
   ds_config.set_enable_extra_guardrails(false);
   auto tmp = base::TempFile::Create();
@@ -68,7 +68,7 @@
   EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "user", tmp.path()));
 }
 
-TEST(CanProfileAndroidTest, UserProfileableAppExtraGuardrails) {
+TEST(CanProfileAndroidTest, UserProfileableByShellAppExtraGuardrails) {
   DataSourceConfig ds_config;
   ds_config.set_enable_extra_guardrails(true);
   auto tmp = base::TempFile::Create();
@@ -80,7 +80,19 @@
   EXPECT_FALSE(CanProfileAndroid(ds_config, 10001, "user", tmp.path()));
 }
 
-TEST(CanProfileAndroidTest, UserProfileableAppMultiuser) {
+TEST(CanProfileAndroidTest, UserProfileableAppExtraGuardrails) {
+  DataSourceConfig ds_config;
+  ds_config.set_enable_extra_guardrails(true);
+  auto tmp = base::TempFile::Create();
+  constexpr char content[] =
+      "invalid.example.profileable 10001 0 "
+      "/data/user/0/invalid.example.profileable default:targetSdkVersion=10000 "
+      "none 2 1\n";
+  base::WriteAll(tmp.fd(), content, sizeof(content));
+  EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "user", tmp.path()));
+}
+
+TEST(CanProfileAndroidTest, UserProfileableByShellAppMultiuser) {
   DataSourceConfig ds_config;
   ds_config.set_enable_extra_guardrails(false);
   auto tmp = base::TempFile::Create();
@@ -92,7 +104,7 @@
   EXPECT_TRUE(CanProfileAndroid(ds_config, 210001, "user", tmp.path()));
 }
 
-TEST(CanProfileAndroidTest, UserNonProfileableApp) {
+TEST(CanProfileAndroidTest, UserNonProfileableByShellApp) {
   DataSourceConfig ds_config;
   ds_config.set_enable_extra_guardrails(false);
   auto tmp = base::TempFile::Create();
diff --git a/src/profiling/perf/unwinding.h b/src/profiling/perf/unwinding.h
index 2eb296f..398747a 100644
--- a/src/profiling/perf/unwinding.h
+++ b/src/profiling/perf/unwinding.h
@@ -17,6 +17,7 @@
 #ifndef SRC_PROFILING_PERF_UNWINDING_H_
 #define SRC_PROFILING_PERF_UNWINDING_H_
 
+#include <condition_variable>
 #include <map>
 #include <thread>
 
diff --git a/src/protozero/protoc_plugin/protozero_plugin.cc b/src/protozero/protoc_plugin/protozero_plugin.cc
index e2d3192..c3dc58b 100644
--- a/src/protozero/protoc_plugin/protozero_plugin.cc
+++ b/src/protozero/protoc_plugin/protozero_plugin.cc
@@ -831,16 +831,25 @@
 
   void GenerateFieldMetadata(const std::string& message_cpp_type,
                              const FieldDescriptor* field) {
-    const char* code_stub =
-        "using $field_metadata_type$ =\n"
-        "  ::protozero::proto_utils::FieldMetadata<\n"
-        "    $field_id$,\n"
-        "    ::protozero::proto_utils::RepetitionType::$repetition_type$,\n"
-        "    ::protozero::proto_utils::ProtoSchemaType::$proto_field_type$,\n"
-        "    $cpp_type$,\n"
-        "    $message_cpp_type$>;\n"
-        "static constexpr const $field_metadata_type$& $field_metadata_var$ = "
-        "{};\n";
+    const char* code_stub = R"(
+using $field_metadata_type$ =
+  ::protozero::proto_utils::FieldMetadata<
+    $field_id$,
+    ::protozero::proto_utils::RepetitionType::$repetition_type$,
+    ::protozero::proto_utils::ProtoSchemaType::$proto_field_type$,
+    $cpp_type$,
+    $message_cpp_type$>;
+
+// Ceci n'est pas une pipe.
+// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
+// type (and users are expected to use it as such, hence kCamelCase name).
+// It is declared as a function to keep protozero bindings header-only as
+// inline constexpr variables are not available until C++17 (while inline
+// functions are).
+// TODO(altimin): Use inline variable instead after adopting C++17.  
+static constexpr $field_metadata_type$ $field_metadata_var$() { return {}; }
+)";
+
     stub_h_->Print(code_stub, "field_id", std::to_string(field->number()),
                    "repetition_type", FieldToRepetitionType(field),
                    "proto_field_type", FieldToProtoSchemaType(field),
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index 16e7908..6c80e87 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -195,16 +195,10 @@
           context_->clock_tracker->ToTraceTime(converted_clock_id, timestamp);
       if (!trace_ts.has_value()) {
         // ToTraceTime() will increase the |clock_sync_failure| stat on failure.
-        static const char seq_extra_err[] =
-            " Because the clock id is sequence-scoped, the ClockSnapshot must "
-            "be emitted on the same TraceWriter sequence of the packet that "
-            "refers to that clock id.";
-        return util::ErrStatus(
-            "Failed to convert TracePacket's timestamp from clock_id=%" PRIu32
-            " seq_id=%" PRIu32
-            ". This is usually due to the lack of a prior ClockSnapshot "
-            "proto.%s",
-            timestamp_clock_id, seq_id, is_seq_scoped ? seq_extra_err : "");
+        // We don't return an error here as it will cause the trace to stop
+        // parsing. Instead, we rely on the stat increment in ToTraceTime() to
+        // inform the user about the error.
+        return util::OkStatus();
       }
       timestamp = trace_ts.value();
     }
diff --git a/src/trace_processor/metrics/android/android_sysui_cuj.sql b/src/trace_processor/metrics/android/android_sysui_cuj.sql
index 67f8ccf..2a0bba1 100644
--- a/src/trace_processor/metrics/android/android_sysui_cuj.sql
+++ b/src/trace_processor/metrics/android/android_sysui_cuj.sql
@@ -277,7 +277,7 @@
     WHERE remainder <> "")
   SELECT frame_number, jank_cause
   FROM split_jank_type
-  WHERE jank_cause NOT IN ('', 'App Deadline Missed', 'None')
+  WHERE jank_cause NOT IN ('', 'App Deadline Missed', 'None', 'Buffer Stuffing')
   ORDER BY frame_number ASC;
 
 DROP TABLE IF EXISTS android_sysui_cuj_missed_frames_hwui_times;
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index d793059..e93c0b4 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -203,7 +203,7 @@
 PERFETTO_TP_TABLE(PERFETTO_TP_PERF_SAMPLE_DEF);
 
 // Symbolization data for a frame. Rows with the same symbol_set_id describe
-// one callframe, with the most-inlined symbol having id == symbol_set_id.
+// one frame, with the bottom-most inlined frame having id == symbol_set_id.
 //
 // For instance, if the function foo has an inlined call to the function bar,
 // which has an inlined call to baz, the stack_profile_symbol table would look
@@ -212,9 +212,9 @@
 // ```
 // |id|symbol_set_id|name         |source_file|line_number|
 // |--|-------------|-------------|-----------|-----------|
-// |1 |      1      |baz          |foo.cc     | 36        |
+// |1 |      1      |foo          |foo.cc     | 60        |
 // |2 |      1      |bar          |foo.cc     | 30        |
-// |3 |      1      |foo          |foo.cc     | 60        |
+// |3 |      1      |baz          |foo.cc     | 36        |
 // ```
 // @param name name of the function.
 // @param source_file name of the source file containing the function.
diff --git a/src/traced/probes/packages_list/packages_list_parser.cc b/src/traced/probes/packages_list/packages_list_parser.cc
index bcbccaa..e00e296 100644
--- a/src/traced/probes/packages_list/packages_list_parser.cc
+++ b/src/traced/probes/packages_list/packages_list_parser.cc
@@ -50,12 +50,13 @@
       }
       case 6: {
         char* end;
-        long long profilable_from_shell = strtoll(ss.cur_token(), &end, 10);
+        long long profilable_level = strtoll(ss.cur_token(), &end, 10);
         if ((*end != '\0' && *end != '\n') || *ss.cur_token() == '\0') {
           PERFETTO_ELOG("Failed to parse packages.list profilable_from_shell.");
           return false;
         }
-        package->profileable_from_shell = profilable_from_shell != 0;
+        package->profileable_from_shell = profilable_level != 0;
+        package->profileable = profilable_level == 2;
         break;
       }
       case 7: {
diff --git a/src/traced/probes/packages_list/packages_list_parser.h b/src/traced/probes/packages_list/packages_list_parser.h
index 3deb3c5..ee35ddd 100644
--- a/src/traced/probes/packages_list/packages_list_parser.h
+++ b/src/traced/probes/packages_list/packages_list_parser.h
@@ -26,6 +26,7 @@
   std::string name;
   uint64_t uid = 0;
   bool debuggable = false;
+  bool profileable = false;
   bool profileable_from_shell = false;
   int64_t version_code = 0;
 };
diff --git a/src/tracing/traced_value_unittest.cc b/src/tracing/traced_value_unittest.cc
index b82d6fc..66c86db 100644
--- a/src/tracing/traced_value_unittest.cc
+++ b/src/tracing/traced_value_unittest.cc
@@ -91,7 +91,7 @@
 ASSERT_TYPE_SUPPORTED(const int*);
 ASSERT_TYPE_SUPPORTED(void*);
 ASSERT_TYPE_SUPPORTED(const void*);
-ASSERT_TYPE_SUPPORTED(nullptr_t);
+ASSERT_TYPE_SUPPORTED(std::nullptr_t);
 ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType*);
 ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType*);
 
diff --git a/test/trace_processor/graphics/android_sysui_cuj.out b/test/trace_processor/graphics/android_sysui_cuj.out
index cf6c74e..1cdea90 100644
--- a/test/trace_processor/graphics/android_sysui_cuj.out
+++ b/test/trace_processor/graphics/android_sysui_cuj.out
@@ -63,7 +63,6 @@
     number: 8
     ts: 400000000
     dur: 10000000
-    jank_cause: "Buffer Stuffing"
     vsync: 120
   }
 }
diff --git a/test/trace_processor/graphics/android_sysui_cuj_event.out b/test/trace_processor/graphics/android_sysui_cuj_event.out
index e36ea72..4519815 100644
--- a/test/trace_processor/graphics/android_sysui_cuj_event.out
+++ b/test/trace_processor/graphics/android_sysui_cuj_event.out
@@ -6,4 +6,3 @@
 "slice","SHADE_ROW_EXPAND - jank cause",70000000,10000000,"RenderThread - scheduler"
 "slice","SHADE_ROW_EXPAND - jank cause",100000000,15000000,"GPU completion - long completion time"
 "slice","SHADE_ROW_EXPAND - jank cause",200000000,15000000,"SurfaceFlinger GPU Deadline Missed,SurfaceFlinger Scheduling"
-"slice","SHADE_ROW_EXPAND - jank cause",400000000,15000000,"Buffer Stuffing"
diff --git a/tools/install-build-deps b/tools/install-build-deps
index 560c1ba..0bfa958 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -208,7 +208,7 @@
     Dependency(
         'buildtools/android-unwinding',
         'https://android.googlesource.com/platform/system/unwinding.git',
-        '5f15cdbdb71db0eb6512e9432a63b8c4075a6c00', 'all', 'all'),
+        'b296bb6fcaa7f59e0ed57bb7a4238ee0f9bfb5bf', 'all', 'all'),
     Dependency('buildtools/android-logging',
                'https://android.googlesource.com/platform/system/logging.git',
                '7b36b566c9113fc703d68f76e8f40c0c2432481c', 'all', 'all'),
diff --git a/tools/trace_processor b/tools/trace_processor
index 5b84f0c..d15dd62 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -21,7 +21,7 @@
 # cat ./trace_processor | python -
 
 BASH_FALLBACK = """ "
-exec python - "$@" <<'#'EOF
+exec python3 - "$@" <<'#'EOF
 #"""
 
 import hashlib
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index 1ef6484..c1674d8 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -71,7 +71,6 @@
     "../../protos/third_party/pprof:zero",
     "../../src/profiling/symbolizer",
     "../../src/profiling/symbolizer:symbolize_database",
-    "../../src/trace_processor/containers:containers",
   ]
   sources = [ "pprof_builder.cc" ]
 }
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc
index e4a9f1d..8384b7a 100644
--- a/tools/trace_to_text/main.cc
+++ b/tools/trace_to_text/main.cc
@@ -32,6 +32,7 @@
 #include "tools/trace_to_text/trace_to_systrace.h"
 #include "tools/trace_to_text/trace_to_text.h"
 
+
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 #include <unistd.h>
 #endif
@@ -42,19 +43,17 @@
 
 int Usage(const char* argv0) {
   fprintf(stderr,
-          "Usage: %s MODE [OPTIONS] [input file] [output file]\n"
-          "modes:\n"
-          "  systrace|json|ctrace|text|profile|hprof|symbolize|deobfuscate\n"
-          "options:\n"
-          "  [--truncate start|end]\n"
-          "  [--full-sort]\n"
-          "\"profile\" mode options:\n"
-          "  [--perf] generate a perf profile instead of a heap profile\n"
-          "  [--no-annotations] do not suffix frame names with derived "
-          "annotations\n"
-          "  [--timestamps TIMESTAMP1,TIMESTAMP2,...] generate profiles "
-          "only for these *specific* timestamps\n"
-          "  [--pid PID] generate profiles only for this process id\n",
+          "Usage: %s systrace|json|ctrace|text|profile [--pid PID] "
+          "[--timestamps TIMESTAMP1,TIMESTAMP2,...] "
+          "[--truncate start|end] "
+          "[--full-sort] "
+          "[trace.pb] "
+          "[trace.txt]\n"
+          "\nProfile mode only:\n"
+          "\t--perf generate a perf profile\n"
+          "\t--timestamps TIMESTAMP1,TIMESTAMP2,... generate profiles "
+          "only for these timestamps\n"
+          "\t--pid PID generate profiles only for this process id\n",
           argv0);
   return 1;
 }
@@ -76,7 +75,6 @@
   std::vector<uint64_t> timestamps;
   bool full_sort = false;
   bool perf_profile = false;
-  bool profile_no_annotations = false;
   for (int i = 1; i < argc; i++) {
     if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
       printf("%s\n", base::GetVersionString());
@@ -105,8 +103,6 @@
       }
     } else if (strcmp(argv[i], "--perf") == 0) {
       perf_profile = true;
-    } else if (strcmp(argv[i], "--no-annotations") == 0) {
-      profile_no_annotations = true;
     } else if (strcmp(argv[i], "--full-sort") == 0) {
       full_sort = true;
     } else {
@@ -191,11 +187,10 @@
     return TraceToText(input_stream, output_stream);
 
   if (format == "profile") {
-    return perf_profile
-               ? TraceToPerfProfile(input_stream, output_stream, pid,
-                                    timestamps, !profile_no_annotations)
-               : TraceToHeapProfile(input_stream, output_stream, pid,
-                                    timestamps, !profile_no_annotations);
+    return perf_profile ? TraceToPerfProfile(input_stream, output_stream, pid,
+                                             timestamps)
+                        : TraceToHeapProfile(input_stream, output_stream, pid,
+                                             timestamps);
   }
 
   if (format == "hprof")
diff --git a/tools/trace_to_text/pprof_builder.cc b/tools/trace_to_text/pprof_builder.cc
index 588c438..fdb8717 100644
--- a/tools/trace_to_text/pprof_builder.cc
+++ b/tools/trace_to_text/pprof_builder.cc
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#include "perfetto/base/build_config.h"
-
 #include "perfetto/profiling/pprof_builder.h"
 
+#include "perfetto/base/build_config.h"
+
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 #include <cxxabi.h>
 #endif
@@ -27,120 +27,29 @@
 #include <algorithm>
 #include <map>
 #include <set>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
 #include "tools/trace_to_text/utils.h"
 
 #include "perfetto/base/logging.h"
-#include "perfetto/ext/base/hash.h"
+#include "perfetto/base/time.h"
 #include "perfetto/ext/base/string_utils.h"
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/protozero/packed_repeated_fields.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
 #include "perfetto/trace_processor/trace_processor.h"
+
 #include "src/profiling/symbolizer/symbolize_database.h"
 #include "src/profiling/symbolizer/symbolizer.h"
-#include "src/trace_processor/containers/string_pool.h"
 
 #include "protos/perfetto/trace/trace.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
 #include "protos/third_party/pprof/profile.pbzero.h"
 
-// Quick hint on navigating the file:
-// Conversions for both perf and heap profiles start with |TraceToPprof|.
-// Non-shared logic is in the |heap_profile| and |perf_profile| namespaces.
-//
-// To build one or more profiles, first the callstack information is queried
-// from the SQL tables, and converted into an in-memory representation by
-// |PreprocessLocations|. Then an instance of |GProfileBuilder| is used to
-// accumulate samples for that profile, and emit all additional information as a
-// serialized proto. Only the entities referenced by that particular
-// |GProfileBuilder| instance are emitted.
-//
-// See protos/third_party/pprof/profile.proto for the meaning of terms like
-// function/location/line.
-
-namespace {
-using StringId = ::perfetto::trace_processor::StringPool::Id;
-
-// In-memory representation of a Profile.Function.
-struct Function {
-  StringId name_id = StringId::Null();
-  StringId system_name_id = StringId::Null();
-  StringId filename_id = StringId::Null();
-
-  Function(StringId n, StringId s, StringId f)
-      : name_id(n), system_name_id(s), filename_id(f) {}
-
-  bool operator==(const Function& other) const {
-    return std::tie(name_id, system_name_id, filename_id) ==
-           std::tie(other.name_id, other.system_name_id, other.filename_id);
-  }
-};
-
-// In-memory representation of a Profile.Line.
-struct Line {
-  int64_t function_id = 0;  // LocationTracker's interned Function id
-  int64_t line_no = 0;
-
-  Line(int64_t func, int64_t line) : function_id(func), line_no(line) {}
-
-  bool operator==(const Line& other) const {
-    return function_id == other.function_id && line_no == other.line_no;
-  }
-};
-
-// In-memory representation of a Profile.Location.
-struct Location {
-  int64_t mapping_id = 0;  // sqlite row id
-  // Common case: location references a single function.
-  int64_t single_function_id = 0;  // interned Function id
-  // Alternatively: multiple inlined functions, recovered via offline
-  // symbolisation. Leaf-first ordering.
-  std::vector<Line> inlined_functions;
-
-  Location(int64_t map, int64_t func, std::vector<Line> inlines)
-      : mapping_id(map),
-        single_function_id(func),
-        inlined_functions(std::move(inlines)) {}
-
-  bool operator==(const Location& other) const {
-    return std::tie(mapping_id, single_function_id, inlined_functions) ==
-           std::tie(other.mapping_id, other.single_function_id,
-                    other.inlined_functions);
-  }
-};
-}  // namespace
-
-template <>
-struct std::hash<Function> {
-  size_t operator()(const Function& loc) const {
-    perfetto::base::Hash hasher;
-    hasher.Update(loc.name_id.raw_id());
-    hasher.Update(loc.system_name_id.raw_id());
-    hasher.Update(loc.filename_id.raw_id());
-    return static_cast<size_t>(hasher.digest());
-  }
-};
-
-template <>
-struct std::hash<Location> {
-  size_t operator()(const Location& loc) const {
-    perfetto::base::Hash hasher;
-    hasher.Update(loc.mapping_id);
-    hasher.Update(loc.single_function_id);
-    for (auto line : loc.inlined_functions) {
-      hasher.Update(line.function_id);
-      hasher.Update(line.line_no);
-    }
-    return static_cast<size_t>(hasher.digest());
-  }
-};
-
 namespace perfetto {
 namespace trace_to_text {
+
 namespace {
 
 using ::perfetto::trace_processor::Iterator;
@@ -174,6 +83,84 @@
   return ret;
 }
 
+// Return map from callsite_id to list of frame_ids that make up the callstack.
+std::vector<std::vector<int64_t>> GetCallsiteToFrames(
+    trace_processor::TraceProcessor* tp) {
+  Iterator count_it =
+      tp->ExecuteQuery("select count(*) from stack_profile_callsite;");
+  if (!count_it.Next()) {
+    PERFETTO_DFATAL_OR_ELOG("Failed to get number of callsites: %s",
+                            count_it.Status().message().c_str());
+    return {};
+  }
+  int64_t count = count_it.Get(0).AsLong();
+
+  Iterator it = tp->ExecuteQuery(
+      "select id, parent_id, frame_id from stack_profile_callsite order by "
+      "depth;");
+  std::vector<std::vector<int64_t>> result(static_cast<size_t>(count));
+  while (it.Next()) {
+    int64_t id = it.Get(0).AsLong();
+    int64_t frame_id = it.Get(2).AsLong();
+    std::vector<int64_t>& path = result[static_cast<size_t>(id)];
+    path.push_back(frame_id);
+
+    auto parent_id_value = it.Get(1);
+    if (!parent_id_value.is_null()) {
+      const std::vector<int64_t>& parent_path =
+          result[static_cast<size_t>(parent_id_value.AsLong())];
+      path.insert(path.end(), parent_path.begin(), parent_path.end());
+    }
+  }
+
+  if (!it.Status().ok()) {
+    PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+                            it.Status().message().c_str());
+    return {};
+  }
+  return result;
+}
+
+base::Optional<int64_t> GetMaxSymbolId(trace_processor::TraceProcessor* tp) {
+  auto max_symbol_id_it =
+      tp->ExecuteQuery("select max(id) from stack_profile_symbol");
+  if (!max_symbol_id_it.Next()) {
+    PERFETTO_DFATAL_OR_ELOG("Failed to get max symbol set id: %s",
+                            max_symbol_id_it.Status().message().c_str());
+    return base::nullopt;
+  }
+  auto value = max_symbol_id_it.Get(0);
+  if (value.is_null())
+    return base::nullopt;
+  return base::make_optional(value.AsLong());
+}
+
+struct Line {
+  int64_t symbol_id;
+  uint32_t line_number;
+};
+
+std::map<int64_t, std::vector<Line>> GetSymbolSetIdToLines(
+    trace_processor::TraceProcessor* tp) {
+  std::map<int64_t, std::vector<Line>> result;
+  Iterator it = tp->ExecuteQuery(
+      "SELECT symbol_set_id, id, line_number FROM stack_profile_symbol;");
+  while (it.Next()) {
+    int64_t symbol_set_id = it.Get(0).AsLong();
+    int64_t id = it.Get(1).AsLong();
+    int64_t line_number = it.Get(2).AsLong();
+    result[symbol_set_id].emplace_back(
+        Line{id, static_cast<uint32_t>(line_number)});
+  }
+
+  if (!it.Status().ok()) {
+    PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+                            it.Status().message().c_str());
+    return {};
+  }
+  return result;
+}
+
 base::Optional<int64_t> GetStatsEntry(
     trace_processor::TraceProcessor* tp,
     const std::string& name,
@@ -195,373 +182,73 @@
   return base::make_optional(it.Get(0).AsLong());
 }
 
-// Interns Locations, Lines, and Functions. Interning is done by the entity's
-// contents, and has no relation to the row ids in the SQL tables.
-// Contains all data for the trace, so can be reused when emitting multiple
-// profiles.
-//
-// TODO(rsavitski): consider moving mappings into here as well. For now, they're
-// still emitted in a single scan during profile building. Mappings should be
-// unique-enough already in the SQL tables, with only incremental state clearing
-// duplicating entries.
-class LocationTracker {
- public:
-  int64_t InternLocation(Location loc) {
-    auto it = locations_.find(loc);
-    if (it == locations_.end()) {
-      bool inserted = false;
-      std::tie(it, inserted) = locations_.emplace(
-          std::move(loc), static_cast<int64_t>(locations_.size()));
-      PERFETTO_DCHECK(inserted);
-    }
-    return it->second;
-  }
-
-  int64_t InternFunction(Function func) {
-    auto it = functions_.find(func);
-    if (it == functions_.end()) {
-      bool inserted = false;
-      std::tie(it, inserted) =
-          functions_.emplace(func, static_cast<int64_t>(functions_.size()));
-      PERFETTO_DCHECK(inserted);
-    }
-    return it->second;
-  }
-
-  bool IsCallsiteProcessed(int64_t callstack_id) const {
-    return callsite_to_locations_.find(callstack_id) !=
-           callsite_to_locations_.end();
-  }
-
-  void MaybeSetCallsiteLocations(int64_t callstack_id,
-                                 const std::vector<int64_t>& locs) {
-    // nop if already set
-    callsite_to_locations_.emplace(callstack_id, locs);
-  }
-
-  const std::vector<int64_t>& LocationsForCallstack(
-      int64_t callstack_id) const {
-    auto it = callsite_to_locations_.find(callstack_id);
-    PERFETTO_CHECK(callstack_id >= 0 && it != callsite_to_locations_.end());
-    return it->second;
-  }
-
-  const std::unordered_map<Location, int64_t>& AllLocations() const {
-    return locations_;
-  }
-  const std::unordered_map<Function, int64_t>& AllFunctions() const {
-    return functions_;
-  }
-
- private:
-  // Root-first location ids for a given callsite id.
-  std::unordered_map<int64_t, std::vector<int64_t>> callsite_to_locations_;
-  std::unordered_map<Location, int64_t> locations_;
-  std::unordered_map<Function, int64_t> functions_;
-};
-
-struct PreprocessedInline {
-  StringId system_name_id = StringId::Null();
-  StringId filename_id = StringId::Null();
-  int64_t line_no = 0;
-
-  PreprocessedInline(StringId s, StringId f, int64_t line)
-      : system_name_id(s), filename_id(f), line_no(line) {}
-};
-
-std::unordered_map<int64_t, std::vector<PreprocessedInline>>
-PreprocessInliningInfo(trace_processor::TraceProcessor* tp,
-                       trace_processor::StringPool* interner) {
-  std::unordered_map<int64_t, std::vector<PreprocessedInline>> inlines;
-
-  // Most-inlined function (leaf) has the lowest id within a symbol set. Query
-  // such that the per-set line vectors are built up leaf-first.
-  Iterator it = tp->ExecuteQuery(
-      "select symbol_set_id, name, source_file, line_number from "
-      "stack_profile_symbol order by symbol_set_id asc, id asc;");
-  while (it.Next()) {
-    int64_t symbol_set_id = it.Get(0).AsLong();
-    auto func_sysname = it.Get(1).is_null() ? "" : it.Get(1).AsString();
-    auto filename = it.Get(2).is_null() ? "" : it.Get(2).AsString();
-    int64_t line_no = it.Get(3).AsLong();
-
-    inlines[symbol_set_id].emplace_back(interner->InternString(func_sysname),
-                                        interner->InternString(filename),
-                                        line_no);
-  }
-
-  if (!it.Status().ok()) {
-    PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
-                            it.Status().message().c_str());
-    return {};
-  }
-  return inlines;
-}
-
-// Extracts and interns the unique frames and locations (as defined by the proto
-// format) from the callstack SQL tables.
-//
-// Approach:
-//   * for each callstack (callsite ids of the leaves):
-//     * use experimental_annotated_callstack to build the full list of
-//       constituent frames
-//     * for each frame (root to leaf):
-//         * intern the location and function(s)
-//         * remember the mapping from callsite_id to the callstack so far (from
-//            the root and including the frame being considered)
-//
-// Optionally mixes in the annotations as a frame name suffix (since there's no
-// good way to attach extra info to locations in the proto format). This relies
-// on the annotations (produced by experimental_annotated_callstack) to be
-// stable for a given callsite (equivalently: dependent only on their parents).
-LocationTracker PreprocessLocations(trace_processor::TraceProcessor* tp,
-                                    trace_processor::StringPool* interner,
-                                    bool annotate_frames) {
-  LocationTracker tracker;
-
-  // Keyed by symbol_set_id, discarded once this function converts the inlines
-  // into Line and Function entries.
-  std::unordered_map<int64_t, std::vector<PreprocessedInline>> inlining_info =
-      PreprocessInliningInfo(tp, interner);
-
-  // Higher callsite ids most likely correspond to the deepest stacks, so we'll
-  // fill more of the overall callsite->location map by visiting the callsited
-  // in decreasing id order. Since processing a callstack also fills in the data
-  // for all parent callsites.
-  Iterator cid_it = tp->ExecuteQuery(
-      "select id from stack_profile_callsite order by id desc;");
-  while (cid_it.Next()) {
-    int64_t query_cid = cid_it.Get(0).AsLong();
-
-    // If the leaf has been processed, the rest of the stack is already known.
-    if (tracker.IsCallsiteProcessed(query_cid))
-      continue;
-
-    std::string annotated_query =
-        "select sp.id, sp.annotation, spf.mapping, "
-        "ifnull(spf.deobfuscated_name, spf.name), spf.symbol_set_id from "
-        "experimental_annotated_callstack(" +
-        std::to_string(query_cid) +
-        ") sp join stack_profile_frame spf on (sp.frame_id == spf.id) "
-        "order by depth asc";
-    Iterator c_it = tp->ExecuteQuery(annotated_query);
-
-    std::vector<int64_t> callstack_loc_ids;
-    while (c_it.Next()) {
-      int64_t cid = c_it.Get(0).AsLong();
-      int64_t mapping_id = c_it.Get(2).AsLong();
-      auto annotation = c_it.Get(1).is_null() ? "" : c_it.Get(1).AsString();
-      auto func_sysname = c_it.Get(3).is_null() ? "" : c_it.Get(3).AsString();
-      base::Optional<int64_t> symbol_set_id =
-          c_it.Get(4).is_null() ? base::nullopt
-                                : base::make_optional(c_it.Get(4).AsLong());
-
-      Location loc(mapping_id, /*single_function_id=*/-1, {});
-
-      auto intern_function = [interner, &tracker, annotate_frames](
-                                 StringId func_sysname_id, StringId filename_id,
-                                 const std::string& anno) {
-        std::string func_name = interner->Get(func_sysname_id).ToStdString();
-        MaybeDemangle(&func_name);
-        if (annotate_frames && !anno.empty() && !func_name.empty())
-          func_name = func_name + " [" + anno + "]";
-        StringId func_name_id =
-            interner->InternString(base::StringView(func_name));
-        Function func(func_name_id, func_sysname_id, filename_id);
-        return tracker.InternFunction(func);
-      };
-
-      // Inlining information available
-      if (symbol_set_id.has_value()) {
-        auto it = inlining_info.find(*symbol_set_id);
-        if (it == inlining_info.end()) {
-          PERFETTO_DFATAL_OR_ELOG(
-              "Failed to find stack_profile_symbol entry for symbol_set_id "
-              "%" PRIi64 "",
-              *symbol_set_id);
-          return {};
-        }
-
-        // N inlined functions
-        for (const auto& line : it->second) {
-          int64_t func_id = intern_function(line.system_name_id,
-                                            line.filename_id, annotation);
-
-          loc.inlined_functions.emplace_back(func_id, line.line_no);
-        }
-      } else {
-        // Otherwise - single function
-        int64_t func_id =
-            intern_function(interner->InternString(func_sysname),
-                            /*filename_id=*/StringId::Null(), annotation);
-        loc.single_function_id = func_id;
-      }
-
-      int64_t loc_id = tracker.InternLocation(std::move(loc));
-
-      // Update the tracker with the locations so far (for example, at depth 2,
-      // we'll have 3 root-most locations in |callstack_loc_ids|).
-      callstack_loc_ids.push_back(loc_id);
-      tracker.MaybeSetCallsiteLocations(cid, callstack_loc_ids);
-    }
-
-    if (!c_it.Status().ok()) {
-      PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
-                              c_it.Status().message().c_str());
-      return {};
-    }
-  }
-
-  if (!cid_it.Status().ok()) {
-    PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
-                            cid_it.Status().message().c_str());
-    return {};
-  }
-
-  return tracker;
-}
-
-// Builds the |perftools.profiles.Profile| proto.
+// Helper for constructing |perftools.profiles.Profile| protos.
 class GProfileBuilder {
  public:
-  GProfileBuilder(const LocationTracker& locations,
-                  trace_processor::StringPool* interner)
-      : locations_(locations), interner_(interner) {
-    // The pprof format requires the first entry in the string table to be the
+  GProfileBuilder(
+      const std::vector<std::vector<int64_t>>& callsite_to_frames,
+      const std::map<int64_t, std::vector<Line>>& symbol_set_id_to_lines,
+      int64_t max_symbol_id)
+      : callsite_to_frames_(callsite_to_frames),
+        symbol_set_id_to_lines_(symbol_set_id_to_lines),
+        max_symbol_id_(max_symbol_id) {
+    // The pprof format expects the first entry in the string table to be the
     // empty string.
-    int64_t empty_id = ToStringTableId(StringId::Null());
+    int64_t empty_id = Intern("");
     PERFETTO_CHECK(empty_id == 0);
   }
 
   void WriteSampleTypes(
       const std::vector<std::pair<std::string, std::string>>& sample_types) {
+    // The interner might eagerly append to the profile proto, prevent it from
+    // breaking up other messages by making a separate pass.
+    for (const auto& st : sample_types) {
+      Intern(st.first);
+      Intern(st.second);
+    }
     for (const auto& st : sample_types) {
       auto* sample_type = result_->add_sample_type();
-      sample_type->set_type(
-          ToStringTableId(interner_->InternString(base::StringView(st.first))));
-      sample_type->set_unit(ToStringTableId(
-          interner_->InternString(base::StringView(st.second))));
+      sample_type->set_type(Intern(st.first));
+      sample_type->set_unit(Intern(st.second));
     }
   }
 
   bool AddSample(const protozero::PackedVarInt& values, int64_t callstack_id) {
-    const auto& location_ids = locations_.LocationsForCallstack(callstack_id);
-    if (location_ids.empty()) {
+    const auto& frames = FramesForCallstack(callstack_id);
+    if (frames.empty()) {
       PERFETTO_DFATAL_OR_ELOG(
           "Failed to find frames for callstack id %" PRIi64 "", callstack_id);
       return false;
     }
-
-    // LocationTracker stores location lists root-first, but the pprof format
-    // requires leaf-first.
-    protozero::PackedVarInt packed_locs;
-    for (auto it = location_ids.rbegin(); it != location_ids.rend(); ++it)
-      packed_locs.Append(ToPprofId(*it));
+    protozero::PackedVarInt location_ids;
+    for (int64_t frame : frames)
+      location_ids.Append(ToPprofId(frame));
 
     auto* gsample = result_->add_sample();
     gsample->set_value(values);
-    gsample->set_location_id(packed_locs);
+    gsample->set_location_id(location_ids);
 
-    // Remember the locations s.t. we only serialize the referenced ones.
-    seen_locations_.insert(location_ids.cbegin(), location_ids.cend());
+    // remember frames to be emitted
+    seen_frames_.insert(frames.cbegin(), frames.cend());
+
     return true;
   }
 
   std::string CompleteProfile(trace_processor::TraceProcessor* tp) {
     std::set<int64_t> seen_mappings;
-    std::set<int64_t> seen_functions;
+    std::set<int64_t> seen_symbol_ids;
 
-    if (!WriteLocations(&seen_mappings, &seen_functions))
-      return {};
-    if (!WriteFunctions(seen_functions))
+    // Write the location info for frames referenced by the added samples.
+    if (!WriteFrames(tp, &seen_mappings, &seen_symbol_ids))
       return {};
     if (!WriteMappings(tp, seen_mappings))
       return {};
-
-    WriteStringTable();
+    if (!WriteSymbols(tp, seen_symbol_ids))
+      return {};
     return result_.SerializeAsString();
   }
 
  private:
-  // Serializes the Profile.Location entries referenced by this profile.
-  bool WriteLocations(std::set<int64_t>* seen_mappings,
-                      std::set<int64_t>* seen_functions) {
-    const std::unordered_map<Location, int64_t>& locations =
-        locations_.AllLocations();
-
-    size_t written_locations = 0;
-    for (const auto& loc_and_id : locations) {
-      const auto& loc = loc_and_id.first;
-      int64_t id = loc_and_id.second;
-
-      if (seen_locations_.find(id) == seen_locations_.end())
-        continue;
-
-      written_locations += 1;
-      seen_mappings->emplace(loc.mapping_id);
-
-      auto* glocation = result_->add_location();
-      glocation->set_id(ToPprofId(id));
-      glocation->set_mapping_id(ToPprofId(loc.mapping_id));
-
-      if (!loc.inlined_functions.empty()) {
-        for (const auto& line : loc.inlined_functions) {
-          seen_functions->insert(line.function_id);
-
-          auto* gline = glocation->add_line();
-          gline->set_function_id(ToPprofId(line.function_id));
-          gline->set_line(line.line_no);
-        }
-      } else {
-        seen_functions->insert(loc.single_function_id);
-
-        glocation->add_line()->set_function_id(
-            ToPprofId(loc.single_function_id));
-      }
-    }
-
-    if (written_locations != seen_locations_.size()) {
-      PERFETTO_DFATAL_OR_ELOG(
-          "Found only %zu/%zu locations during serialization.",
-          written_locations, seen_locations_.size());
-      return false;
-    }
-    return true;
-  }
-
-  // Serializes the Profile.Function entries referenced by this profile.
-  bool WriteFunctions(const std::set<int64_t>& seen_functions) {
-    const std::unordered_map<Function, int64_t>& functions =
-        locations_.AllFunctions();
-
-    size_t written_functions = 0;
-    for (const auto& func_and_id : functions) {
-      const auto& func = func_and_id.first;
-      int64_t id = func_and_id.second;
-
-      if (seen_functions.find(id) == seen_functions.end())
-        continue;
-
-      written_functions += 1;
-
-      auto* gfunction = result_->add_function();
-      gfunction->set_id(ToPprofId(id));
-      gfunction->set_name(ToStringTableId(func.name_id));
-      gfunction->set_system_name(ToStringTableId(func.system_name_id));
-      if (!func.filename_id.is_null())
-        gfunction->set_filename(ToStringTableId(func.filename_id));
-    }
-
-    if (written_functions != seen_functions.size()) {
-      PERFETTO_DFATAL_OR_ELOG(
-          "Found only %zu/%zu functions during serialization.",
-          written_functions, seen_functions.size());
-      return false;
-    }
-    return true;
-  }
-
-  // Serializes the Profile.Mapping entries referenced by this profile.
   bool WriteMappings(trace_processor::TraceProcessor* tp,
                      const std::set<int64_t>& seen_mappings) {
     Iterator mapping_it = tp->ExecuteQuery(
@@ -573,8 +260,7 @@
       if (seen_mappings.find(id) == seen_mappings.end())
         continue;
       ++mappings_no;
-      auto interned_filename = ToStringTableId(
-          interner_->InternString(mapping_it.Get(4).AsString()));
+      auto interned_filename = Intern(mapping_it.Get(4).AsString());
       auto* gmapping = result_->add_mapping();
       gmapping->set_id(ToPprofId(id));
       // Do not set the build_id here to avoid downstream services
@@ -599,48 +285,145 @@
     return true;
   }
 
-  void WriteStringTable() {
-    for (StringId id : string_table_) {
-      trace_processor::NullTermStringView s = interner_->Get(id);
-      result_->add_string_table(s.data(), s.size());
+  bool WriteSymbols(trace_processor::TraceProcessor* tp,
+                    const std::set<int64_t>& seen_symbol_ids) {
+    Iterator symbol_it = tp->ExecuteQuery(
+        "SELECT id, name, source_file FROM stack_profile_symbol");
+    size_t symbols_no = 0;
+    while (symbol_it.Next()) {
+      int64_t id = symbol_it.Get(0).AsLong();
+      if (seen_symbol_ids.find(id) == seen_symbol_ids.end())
+        continue;
+      ++symbols_no;
+      const std::string& name = symbol_it.Get(1).AsString();
+      std::string demangled_name = name;
+      MaybeDemangle(&demangled_name);
+
+      auto interned_demangled_name = Intern(demangled_name);
+      auto interned_system_name = Intern(name);
+      auto interned_filename = Intern(symbol_it.Get(2).AsString());
+      auto* gfunction = result_->add_function();
+      gfunction->set_id(ToPprofId(id));
+      gfunction->set_name(interned_demangled_name);
+      gfunction->set_system_name(interned_system_name);
+      gfunction->set_filename(interned_filename);
     }
+
+    if (!symbol_it.Status().ok()) {
+      PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+                              symbol_it.Status().message().c_str());
+      return false;
+    }
+
+    if (symbols_no != seen_symbol_ids.size()) {
+      PERFETTO_DFATAL_OR_ELOG("Missing symbols.");
+      return false;
+    }
+    return true;
   }
 
-  int64_t ToStringTableId(StringId interned_id) {
-    auto it = interning_remapper_.find(interned_id);
-    if (it == interning_remapper_.end()) {
-      int64_t table_id = static_cast<int64_t>(string_table_.size());
-      string_table_.push_back(interned_id);
-      bool inserted = false;
-      std::tie(it, inserted) =
-          interning_remapper_.emplace(interned_id, table_id);
-      PERFETTO_DCHECK(inserted);
+  bool WriteFrames(trace_processor::TraceProcessor* tp,
+                   std::set<int64_t>* seen_mappings,
+                   std::set<int64_t>* seen_symbol_ids) {
+    Iterator frame_it = tp->ExecuteQuery(
+        "SELECT spf.id, IFNULL(spf.deobfuscated_name, spf.name), spf.mapping, "
+        "spf.rel_pc, spf.symbol_set_id "
+        "FROM stack_profile_frame spf;");
+    size_t frames_no = 0;
+    while (frame_it.Next()) {
+      int64_t frame_id = frame_it.Get(0).AsLong();
+      if (seen_frames_.find(frame_id) == seen_frames_.end())
+        continue;
+      frames_no++;
+      std::string frame_name = frame_it.Get(1).AsString();
+      int64_t mapping_id = frame_it.Get(2).AsLong();
+      int64_t rel_pc = frame_it.Get(3).AsLong();
+      base::Optional<int64_t> symbol_set_id;
+      if (!frame_it.Get(4).is_null())
+        symbol_set_id = frame_it.Get(4).AsLong();
+
+      seen_mappings->emplace(mapping_id);
+      auto* glocation = result_->add_location();
+      glocation->set_id(ToPprofId(frame_id));
+      glocation->set_mapping_id(ToPprofId(mapping_id));
+      // TODO(fmayer): Convert to abspc.
+      // relpc + (mapping.start - (mapping.exact_offset -
+      //                           mapping.start_offset)).
+      glocation->set_address(static_cast<uint64_t>(rel_pc));
+      if (symbol_set_id) {
+        for (const Line& line : LineForSymbolSetId(*symbol_set_id)) {
+          seen_symbol_ids->emplace(line.symbol_id);
+          auto* gline = glocation->add_line();
+          gline->set_line(line.line_number);
+          gline->set_function_id(ToPprofId(line.symbol_id));
+        }
+      } else {
+        int64_t synthesized_symbol_id = ++max_symbol_id_;
+        std::string demangled_name = frame_name;
+        MaybeDemangle(&demangled_name);
+
+        auto* gline = glocation->add_line();
+        gline->set_line(0);
+        gline->set_function_id(ToPprofId(synthesized_symbol_id));
+
+        auto interned_demangled_name = Intern(demangled_name);
+        auto interned_system_name = Intern(frame_name);
+        auto* gfunction = result_->add_function();
+        gfunction->set_id(ToPprofId(synthesized_symbol_id));
+        gfunction->set_name(interned_demangled_name);
+        gfunction->set_system_name(interned_system_name);
+      }
+    }
+
+    if (!frame_it.Status().ok()) {
+      PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+                              frame_it.Status().message().c_str());
+      return false;
+    }
+    if (frames_no != seen_frames_.size()) {
+      PERFETTO_DFATAL_OR_ELOG("Missing frames.");
+      return false;
+    }
+    return true;
+  }
+
+  const std::vector<int64_t>& FramesForCallstack(int64_t callstack_id) {
+    size_t callsite_idx = static_cast<size_t>(callstack_id);
+    PERFETTO_CHECK(callstack_id >= 0 &&
+                   callsite_idx < callsite_to_frames_.size());
+    return callsite_to_frames_[callsite_idx];
+  }
+
+  const std::vector<Line>& LineForSymbolSetId(int64_t symbol_set_id) {
+    auto it = symbol_set_id_to_lines_.find(symbol_set_id);
+    if (it == symbol_set_id_to_lines_.end())
+      return empty_line_vector_;
+    return it->second;
+  }
+
+  int64_t Intern(const std::string& s) {
+    auto it = string_table_.find(s);
+    if (it == string_table_.end()) {
+      std::tie(it, std::ignore) =
+          string_table_.emplace(s, string_table_.size());
+      result_->add_string_table(s);
     }
     return it->second;
   }
 
-  // Contains all locations, lines, functions (in memory):
-  const LocationTracker& locations_;
-
-  // String interner, strings referenced by LocationTracker are already
-  // interned. The new internings will come from mappings, and sample types.
-  trace_processor::StringPool* interner_;
-
-  // The profile format uses the repeated string_table field's index as an
-  // implicit id, so these structures remap the interned strings into sequential
-  // ids. Only the strings referenced by this GProfileBuilder instance will be
-  // added to the table.
-  std::unordered_map<StringId, int64_t> interning_remapper_;
-  std::vector<StringId> string_table_;
-
-  // Profile proto being serialized.
   protozero::HeapBuffered<third_party::perftools::profiles::pbzero::Profile>
       result_;
+  std::map<std::string, int64_t> string_table_;
+  const std::vector<std::vector<int64_t>>& callsite_to_frames_;
+  const std::map<int64_t, std::vector<Line>>& symbol_set_id_to_lines_;
+  const std::vector<Line> empty_line_vector_;
+  int64_t max_symbol_id_;
 
-  // Set of locations referenced by the added samples.
-  std::set<int64_t> seen_locations_;
+  std::set<int64_t> seen_frames_;
 };
 
+}  // namespace
+
 namespace heap_profile {
 struct View {
   const char* type;
@@ -760,12 +543,13 @@
 
 static bool TraceToHeapPprof(trace_processor::TraceProcessor* tp,
                              std::vector<SerializedProfile>* output,
-                             bool annotate_frames,
                              uint64_t target_pid,
                              const std::vector<uint64_t>& target_timestamps) {
-  trace_processor::StringPool interner;
-  LocationTracker locations =
-      PreprocessLocations(tp, &interner, annotate_frames);
+  const auto callsite_to_frames = GetCallsiteToFrames(tp);
+  const auto symbol_set_id_to_lines = GetSymbolSetIdToLines(tp);
+  base::Optional<int64_t> max_symbol_id = GetMaxSymbolId(tp);
+  if (!max_symbol_id.has_value())
+    return false;
 
   bool any_fail = false;
   Iterator it = tp->ExecuteQuery(
@@ -773,7 +557,8 @@
       "from heap_profile_allocation hpa, "
       "process p where p.upid = hpa.upid;");
   while (it.Next()) {
-    GProfileBuilder builder(locations, &interner);
+    GProfileBuilder builder(callsite_to_frames, symbol_set_id_to_lines,
+                            max_symbol_id.value());
     uint64_t upid = static_cast<uint64_t>(it.Get(0).AsLong());
     uint64_t ts = static_cast<uint64_t>(it.Get(1).AsLong());
     uint64_t profile_pid = static_cast<uint64_t>(it.Get(2).AsLong());
@@ -901,11 +686,12 @@
 // perf and heap profiles.
 static bool TraceToPerfPprof(trace_processor::TraceProcessor* tp,
                              std::vector<SerializedProfile>* output,
-                             bool annotate_frames,
                              uint64_t target_pid) {
-  trace_processor::StringPool interner;
-  LocationTracker locations =
-      PreprocessLocations(tp, &interner, annotate_frames);
+  const auto callsite_to_frames = GetCallsiteToFrames(tp);
+  const auto symbol_set_id_to_lines = GetSymbolSetIdToLines(tp);
+  base::Optional<int64_t> max_symbol_id = GetMaxSymbolId(tp);
+  if (!max_symbol_id.has_value())
+    return false;
 
   LogTracePerfEventIssues(tp);
 
@@ -917,7 +703,9 @@
     if (target_pid != 0 && process.pid != target_pid)
       continue;
 
-    GProfileBuilder builder(locations, &interner);
+    GProfileBuilder builder(callsite_to_frames, symbol_set_id_to_lines,
+                            max_symbol_id.value());
+
     builder.WriteSampleTypes({{"samples", "count"}});
 
     std::string query = "select callsite_id from perf_sample where utid in (" +
@@ -945,22 +733,17 @@
   return true;
 }
 }  // namespace perf_profile
-}  // namespace
 
 bool TraceToPprof(trace_processor::TraceProcessor* tp,
                   std::vector<SerializedProfile>* output,
                   ConversionMode mode,
-                  uint64_t flags,
                   uint64_t pid,
                   const std::vector<uint64_t>& timestamps) {
-  bool annotate_frames =
-      flags & static_cast<uint64_t>(ConversionFlags::kAnnotateFrames);
   switch (mode) {
     case (ConversionMode::kHeapProfile):
-      return heap_profile::TraceToHeapPprof(tp, output, annotate_frames, pid,
-                                            timestamps);
+      return heap_profile::TraceToHeapPprof(tp, output, pid, timestamps);
     case (ConversionMode::kPerfProfile):
-      return perf_profile::TraceToPerfPprof(tp, output, annotate_frames, pid);
+      return perf_profile::TraceToPerfPprof(tp, output, pid);
   }
   PERFETTO_FATAL("unknown conversion option");  // for gcc
 }
diff --git a/tools/trace_to_text/trace_to_profile.cc b/tools/trace_to_text/trace_to_profile.cc
index c71a827..a394e2b 100644
--- a/tools/trace_to_text/trace_to_profile.cc
+++ b/tools/trace_to_text/trace_to_profile.cc
@@ -50,12 +50,6 @@
 namespace trace_to_text {
 namespace {
 
-uint64_t ToConversionFlags(bool annotate_frames) {
-  return static_cast<uint64_t>(annotate_frames
-                                   ? ConversionFlags::kAnnotateFrames
-                                   : ConversionFlags::kNone);
-}
-
 std::string GetRandomString(size_t n) {
   std::random_device r;
   auto rng = std::default_random_engine(r());
@@ -98,7 +92,6 @@
     uint64_t pid,
     std::vector<uint64_t> timestamps,
     ConversionMode conversion_mode,
-    uint64_t conversion_flags,
     std::string dirname_prefix,
     std::function<std::string(const SerializedProfile&)> filename_fn) {
   std::vector<SerializedProfile> profiles;
@@ -113,8 +106,7 @@
   MaybeSymbolize(tp.get());
   MaybeDeobfuscate(tp.get());
 
-  TraceToPprof(tp.get(), &profiles, conversion_mode, conversion_flags, pid,
-               timestamps);
+  TraceToPprof(tp.get(), &profiles, conversion_mode, pid, timestamps);
   if (profiles.empty()) {
     return 0;
   }
@@ -140,33 +132,31 @@
 int TraceToHeapProfile(std::istream* input,
                        std::ostream* output,
                        uint64_t pid,
-                       std::vector<uint64_t> timestamps,
-                       bool annotate_frames) {
+                       std::vector<uint64_t> timestamps) {
   int file_idx = 0;
   auto filename_fn = [&file_idx](const SerializedProfile& profile) {
     return "heap_dump." + std::to_string(++file_idx) + "." +
            std::to_string(profile.pid) + "." + profile.heap_name + ".pb";
   };
 
-  return TraceToProfile(
-      input, output, pid, timestamps, ConversionMode::kHeapProfile,
-      ToConversionFlags(annotate_frames), "heap_profile-", filename_fn);
+  return TraceToProfile(input, output, pid, timestamps,
+                        ConversionMode::kHeapProfile, "heap_profile-",
+                        filename_fn);
 }
 
 int TraceToPerfProfile(std::istream* input,
                        std::ostream* output,
                        uint64_t pid,
-                       std::vector<uint64_t> timestamps,
-                       bool annotate_frames) {
+                       std::vector<uint64_t> timestamps) {
   int file_idx = 0;
   auto filename_fn = [&file_idx](const SerializedProfile& profile) {
     return "profile." + std::to_string(++file_idx) + ".pid." +
            std::to_string(profile.pid) + ".pb";
   };
 
-  return TraceToProfile(
-      input, output, pid, timestamps, ConversionMode::kPerfProfile,
-      ToConversionFlags(annotate_frames), "perf_profile-", filename_fn);
+  return TraceToProfile(input, output, pid, timestamps,
+                        ConversionMode::kPerfProfile, "perf_profile-",
+                        filename_fn);
 }
 
 }  // namespace trace_to_text
diff --git a/tools/trace_to_text/trace_to_profile.h b/tools/trace_to_text/trace_to_profile.h
index 313b32b..1c41aad 100644
--- a/tools/trace_to_text/trace_to_profile.h
+++ b/tools/trace_to_text/trace_to_profile.h
@@ -27,15 +27,13 @@
 int TraceToHeapProfile(std::istream* input,
                        std::ostream* output,
                        uint64_t pid,
-                       std::vector<uint64_t> timestamps,
-                       bool annotate_frames);
+                       std::vector<uint64_t> timestamps);
 
 // 0: success
 int TraceToPerfProfile(std::istream* input,
                        std::ostream* output,
                        uint64_t pid,
-                       std::vector<uint64_t> timestamps,
-                       bool annotate_frames);
+                       std::vector<uint64_t> timestamps);
 
 }  // namespace trace_to_text
 }  // namespace perfetto
diff --git a/tools/traceconv b/tools/traceconv
index c0cff60..bb90486 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -21,7 +21,7 @@
 # cat ./traceconv | python -
 
 BASH_FALLBACK = """ "
-exec python - "$@" <<'#'EOF
+exec python3 - "$@" <<'#'EOF
 #"""
 
 import hashlib
diff --git a/tools/write_version_header.py b/tools/write_version_header.py
index 0325f6f..dd02a69 100755
--- a/tools/write_version_header.py
+++ b/tools/write_version_header.py
@@ -123,7 +123,7 @@
     guard = '%s_' % args.cpp_out.upper()
     guard = re.sub(r'[^\w]', '_', guard)
     lines = []
-    lines.append('// Generated by %s' % __file__)
+    lines.append('// Generated by %s' % os.path.basename(__file__))
     lines.append('')
     lines.append('#ifndef %s' % guard)
     lines.append('#define %s' % guard)
diff --git a/ui/release/channels.json b/ui/release/channels.json
index 6d53d32..160b544 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -2,11 +2,11 @@
   "channels": [
     {
       "name": "stable",
-      "rev": "b7ab2469bd84ac0a4883c7f6a8a67e73903459b0"
+      "rev": "06350fe212f5051d9e890411ca24ab4a84b33ae1"
     },
     {
       "name": "canary",
-      "rev": "06350fe212f5051d9e890411ca24ab4a84b33ae1"
+      "rev": "aaab326dc5b38858d516171ba68f4542e9e92d65"
     },
     {
       "name": "autopush",
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 65c78d0..8d47424 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -519,11 +519,13 @@
     'accessibility',
     'AccountFetcherService',
     'android_webview',
+    'aogh',
     'audio',
     'base',
     'benchmark',
     'blink',
     'blink.animations',
+    'blink.bindings',
     'blink.console',
     'blink_gc',
     'blink.net',
@@ -534,8 +536,13 @@
     'browser',
     'browsing_data',
     'CacheStorage',
+    'Calculators',
+    'CameraStream',
     'camera',
+    'cast_app',
     'cast_perf_test',
+    'cast.mdns',
+    'cast.mdns.socket',
     'cast.stream',
     'cc',
     'cc.debug',
@@ -545,14 +552,17 @@
     'compositor',
     'content',
     'content_capture',
+    'device',
     'devtools',
+    'devtools.contrast',
     'devtools.timeline',
+    'disk_cache',
     'download',
     'download_service',
     'drm',
     'drmcursor',
     'dwrite',
-    'DXVA Decoding',
+    'DXVA_Decoding',
     'EarlyJava',
     'evdev',
     'event',
@@ -563,10 +573,12 @@
     'fonts',
     'GAMEPAD',
     'gpu',
+    'gpu.angle',
     'gpu.capture',
     'headless',
     'hwoverlays',
     'identity',
+    'ime',
     'IndexedDB',
     'input',
     'io',
@@ -594,12 +606,17 @@
     'omnibox',
     'oobe',
     'ozone',
+    'partition_alloc',
     'passwords',
     'p2p',
     'page-serialization',
+    'paint_preview',
     'pepper',
+    'PlatformMalloc',
+    'power',
     'ppapi',
-    'ppapi proxy',
+    'ppapi_proxy',
+    'print',
     'rail',
     'renderer',
     'renderer_host',
@@ -610,21 +627,26 @@
     'sequence_manager',
     'service_manager',
     'ServiceWorker',
+    'sharing',
     'shell',
     'shortcut_viewer',
     'shutdown',
     'SiteEngagement',
     'skia',
+    'sql',
+    'stadia_media',
+    'stadia_rtc',
     'startup',
     'sync',
     'sync_lock_contention',
-    'thread_pool',
     'test_gpu',
-    'test_tracing',
+    'thread_pool',
     'toplevel',
+    'toplevel.flow',
     'ui',
     'v8',
     'v8.execute',
+    'v8.wasm',
     'ValueStoreFrontend::Backend',
     'views',
     'views.frame',
@@ -637,6 +659,7 @@
     'webrtc',
     'xr',
     'disabled-by-default-animation-worklet',
+    'disabled-by-default-audio',
     'disabled-by-default-audio-worklet',
     'disabled-by-default-blink.debug',
     'disabled-by-default-blink.debug.display_lock',
@@ -654,6 +677,7 @@
     'disabled-by-default-cc.debug.scheduler',
     'disabled-by-default-cc.debug.scheduler.frames',
     'disabled-by-default-cc.debug.scheduler.now',
+    'disabled-by-default-content.verbose',
     'disabled-by-default-cpu_profiler',
     'disabled-by-default-cpu_profiler.debug',
     'disabled-by-default-devtools.screenshot',
@@ -668,34 +692,41 @@
     'disabled-by-default-gpu_cmd_queue',
     'disabled-by-default-gpu.dawn',
     'disabled-by-default-gpu.debug',
-    'disabled-by-default-gpu_decoder',
+    'disabled-by-default-gpu.decoder',
     'disabled-by-default-gpu.device',
     'disabled-by-default-gpu.service',
+    'disabled-by-default-gpu.vulkan.vma',
     'disabled-by-default-histogram_samples',
     'disabled-by-default-ipc.flow',
     'disabled-by-default-java-heap-profiler',
     'disabled-by-default-layer-element',
+    'disabled-by-default-layout_shift.debug',
     'disabled-by-default-lifecycles',
     'disabled-by-default-loading',
+    'disabled-by-default-mediastream',
     'disabled-by-default-memory-infra',
     'disabled-by-default-memory-infra.v8.code_stats',
+    'disabled-by-default-mojom',
     'disabled-by-default-net',
     'disabled-by-default-network',
     'disabled-by-default-paint-worklet',
     'disabled-by-default-power',
     'disabled-by-default-renderer.scheduler',
     'disabled-by-default-renderer.scheduler.debug',
+    'disabled-by-default-sandbox',
     'disabled-by-default-sequence_manager',
     'disabled-by-default-sequence_manager.debug',
     'disabled-by-default-sequence_manager.verbose_snapshots',
     'disabled-by-default-skia',
     'disabled-by-default-skia.gpu',
     'disabled-by-default-skia.gpu.cache',
+    'disabled-by-default-skia.shaders',
     'disabled-by-default-SyncFileSystem',
     'disabled-by-default-system_stats',
     'disabled-by-default-thread_pool_diagnostics',
     'disabled-by-default-toplevel.flow',
     'disabled-by-default-toplevel.ipc',
+    'disabled-by-default-user_action_samples',
     'disabled-by-default-v8.compile',
     'disabled-by-default-v8.cpu_profiler',
     'disabled-by-default-v8.cpu_profiler.hires',
@@ -705,17 +736,24 @@
     'disabled-by-default-v8.runtime',
     'disabled-by-default-v8.runtime_stats',
     'disabled-by-default-v8.runtime_stats_sampling',
+    'disabled-by-default-v8.stack_trace',
     'disabled-by-default-v8.turbofan',
     'disabled-by-default-v8.wasm',
+    'disabled-by-default-v8.wasm.detailed',
+    'disabled-by-default-v8.wasm.turbofan',
     'disabled-by-default-video_and_image_capture',
     'disabled-by-default-viz.debug.overlay_planes',
+    'disabled-by-default-viz.gpu_composite_time',
     'disabled-by-default-viz.hit_testing_flow',
     'disabled-by-default-viz.overdraw',
     'disabled-by-default-viz.quads',
     'disabled-by-default-viz.surface_id_flow',
     'disabled-by-default-viz.surface_lifetime',
     'disabled-by-default-viz.triangles',
+    'disabled-by-default-webaudio.audionode',
+    'disabled-by-default-webrtc',
     'disabled-by-default-worker.scheduler',
+    'disabled-by-default-xr.debug',
   ];
 }