Merge "stdlib: OOM score" into main
diff --git a/bazel/proto_gen.bzl b/bazel/proto_gen.bzl
index c5fd127..e237ebc 100644
--- a/bazel/proto_gen.bzl
+++ b/bazel/proto_gen.bzl
@@ -46,13 +46,17 @@
         strip_base_path = ctx.label.package + "/"
     elif ctx.label.workspace_root:
         # This path is hit when proto targets are built as @perfetto//:xxx
-        # instead of //:xxx. This happens in embedder builds. In this case,
-        # workspace_root == "external/perfetto" and we need to rebase the paths
-        # passed to protoc.
+        # instead of //:xxx. This happens in embedder builds.
         proto_path = ctx.label.workspace_root
-        out_dir += "/" + ctx.label.workspace_root
+
+        # We could be using the sibling repository layout, in which case we do nothing.
+        if not ctx.label.workspace_root.startswith("../"):
+            # workspace_root == "external/perfetto" and we need to rebase the paths
+            # passed to protoc.
+            out_dir += "/" + ctx.label.workspace_root
         strip_base_path = ctx.label.workspace_root + "/"
 
+
     out_files = []
     suffix = ctx.attr.suffix
     for src in proto_src:
diff --git a/docs/reference/perfetto-cli.md b/docs/reference/perfetto-cli.md
index 195ceb1..377502e 100644
--- a/docs/reference/perfetto-cli.md
+++ b/docs/reference/perfetto-cli.md
@@ -124,7 +124,7 @@
 :    Specifies the path to a configuration file. In normal mode, some
      configurations may be encoded in a configuration protocol buffer.
      This file must comply with the protocol buffer schema defined in AOSP
-     [`trace_config.proto`](/protos/perfetto/config/data_source_config.proto).
+     [`trace_config.proto`](/protos/perfetto/config/trace_config.proto).
      You select and configure the data sources using the DataSourceConfig member
      of the TraceConfig, as defined in AOSP
      [`data_source_config.proto`](/protos/perfetto/config/data_source_config.proto).
diff --git a/gn/standalone/protoc.py b/gn/standalone/protoc.py
index 52e156e..bd8913f 100644
--- a/gn/standalone/protoc.py
+++ b/gn/standalone/protoc.py
@@ -16,45 +16,9 @@
 This script exists to work-around the bad depfile generation by protoc when
 generating descriptors."""
 
-from __future__ import print_function
-import argparse
-import os
 import sys
 import subprocess
-import tempfile
-import uuid
-
-from codecs import open
-
-
-def main():
-  parser = argparse.ArgumentParser()
-  parser.add_argument('--descriptor_set_out', default=None)
-  parser.add_argument('--dependency_out', default=None)
-  parser.add_argument('protoc')
-  args, remaining = parser.parse_known_args()
-
-  if args.dependency_out and args.descriptor_set_out:
-    tmp_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4()))
-    custom = [
-        '--descriptor_set_out', args.descriptor_set_out, '--dependency_out',
-        tmp_path
-    ]
-    try:
-      cmd = [args.protoc] + custom + remaining
-      subprocess.check_call(cmd)
-      with open(tmp_path, 'rb') as tmp_rd:
-        dependency_data = tmp_rd.read().decode('utf-8')
-    finally:
-      if os.path.exists(tmp_path):
-        os.unlink(tmp_path)
-
-    with open(args.dependency_out, 'w', encoding='utf-8') as f:
-      f.write(args.descriptor_set_out + ":")
-      f.write(dependency_data)
-  else:
-    subprocess.check_call(sys.argv[1:])
 
 
 if __name__ == '__main__':
-  sys.exit(main())
+  sys.exit(subprocess.call(sys.argv[1:]))
diff --git a/include/perfetto/ext/base/getopt.h b/include/perfetto/ext/base/getopt.h
index bf993fc..abf8cca 100644
--- a/include/perfetto/ext/base/getopt.h
+++ b/include/perfetto/ext/base/getopt.h
@@ -45,7 +45,7 @@
     ::perfetto::base::getopt_compat::required_argument;
 
 #else
-#include <getopt.h>
+#include <getopt.h>  // IWYU pragma: export
 #endif
 
 #endif  // INCLUDE_PERFETTO_EXT_BASE_GETOPT_H_
diff --git a/protos/perfetto/common/observable_events.proto b/protos/perfetto/common/observable_events.proto
index 85767a6..b841a0b 100644
--- a/protos/perfetto/common/observable_events.proto
+++ b/protos/perfetto/common/observable_events.proto
@@ -63,6 +63,9 @@
     // consumer has no idea of what is the TSID of its own tracing session and
     // there is no other good way to plumb it.
     optional int64 tracing_session_id = 1;
+
+    // The trigger name of the CLONE_SNAPSHOT trigger which was hit.
+    optional string trigger_name = 2;
   }
 
   repeated DataSourceInstanceStateChange instance_state_changes = 1;
diff --git a/protos/perfetto/trace/android/BUILD.gn b/protos/perfetto/trace/android/BUILD.gn
index 900a64b..90234da 100644
--- a/protos/perfetto/trace/android/BUILD.gn
+++ b/protos/perfetto/trace/android/BUILD.gn
@@ -15,7 +15,10 @@
 import("../../../../gn/proto_library.gni")
 
 perfetto_proto_library("@TYPE@") {
-  deps = [ "../../common:@TYPE@", ":winscope_regular_@TYPE@" ]
+  deps = [
+    ":winscope_regular_@TYPE@",
+    "../../common:@TYPE@",
+  ]
 
   sources = [
     "android_game_intervention_list.proto",
@@ -44,8 +47,8 @@
 # Winscope messages added to TracePacket directly
 perfetto_proto_library("winscope_regular_@TYPE@") {
   deps = [
-    "../../common:@TYPE@",
     ":winscope_common_@TYPE@",
+    "../../common:@TYPE@",
   ]
   sources = [
     "protolog.proto",
@@ -64,19 +67,19 @@
   ]
   public_deps = [ ":winscope_common_@TYPE@" ]
   sources = [
-    "inputmethodeditor.proto",
     "graphics/pixelformat.proto",
+    "inputmethodeditor.proto",
     "inputmethodservice/inputmethodservice.proto",
     "inputmethodservice/softinputwindow.proto",
     "server/inputmethod/inputmethodmanagerservice.proto",
     "typedef.proto",
-    "view/inputmethod/editorinfo.proto",
-    "view/inputmethod/inputconnection.proto",
-    "view/inputmethod/inputmethodmanager.proto",
     "view/display.proto",
     "view/displaycutout.proto",
     "view/imefocuscontroller.proto",
     "view/imeinsetssourceconsumer.proto",
+    "view/inputmethod/editorinfo.proto",
+    "view/inputmethod/inputconnection.proto",
+    "view/inputmethod/inputmethodmanager.proto",
     "view/insetsanimationcontrolimpl.proto",
     "view/insetscontroller.proto",
     "view/insetssource.proto",
@@ -95,8 +98,8 @@
   proto_generators = [ "descriptor" ]
   generate_descriptor = "winscope.descriptor"
   deps = [
-    ":winscope_regular_source_set",
     ":winscope_extensions_source_set",
+    ":winscope_regular_source_set",
   ]
   sources = [ "winscope.proto" ]
   import_dirs = [ "${perfetto_protobuf_src_dir}" ]
diff --git a/src/android_internal/statsd_logging.cc b/src/android_internal/statsd_logging.cc
index a164adf..09b55a2 100644
--- a/src/android_internal/statsd_logging.cc
+++ b/src/android_internal/statsd_logging.cc
@@ -16,12 +16,11 @@
 
 #include "src/android_internal/statsd_logging.h"
 
-#include <string.h>
+#include <cstdint>
 
 #include <statslog_perfetto.h>
 
-namespace perfetto {
-namespace android_internal {
+namespace perfetto::android_internal {
 
 void StatsdLogUploadEvent(PerfettoStatsdAtom atom,
                           int64_t uuid_lsb,
@@ -35,5 +34,4 @@
   stats_write(PERFETTO_TRIGGER, static_cast<int32_t>(atom), trigger_name);
 }
 
-}  // namespace android_internal
-}  // namespace perfetto
+}  // namespace perfetto::android_internal
diff --git a/src/android_stats/perfetto_atoms.h b/src/android_stats/perfetto_atoms.h
index 1981a77..6352042 100644
--- a/src/android_stats/perfetto_atoms.h
+++ b/src/android_stats/perfetto_atoms.h
@@ -27,6 +27,8 @@
   // Checkpoints inside perfetto_cmd before tracing is finished.
   kTraceBegin = 1,
   kBackgroundTraceBegin = 2,
+  kCloneTraceBegin = 55,
+  kCloneTriggerTraceBegin = 56,
   kOnConnect = 3,
 
   // Guardrails inside perfetto_cmd before tracing is finished.
@@ -105,7 +107,7 @@
   // longer supports uploading traces using Dropbox.
   // reserved 5, 6, 7;
 
-  // Contained status of guardrail state initalization and upload limit in
+  // Contained status of guardrail state initialization and upload limit in
   // perfetto_cmd. Removed as perfetto no longer manages stateful guardrails
   // reserved 44, 45, 46;
 };
diff --git a/src/android_stats/statsd_logging_helper.cc b/src/android_stats/statsd_logging_helper.cc
index c943027..1f5011a 100644
--- a/src/android_stats/statsd_logging_helper.cc
+++ b/src/android_stats/statsd_logging_helper.cc
@@ -16,10 +16,12 @@
 
 #include "src/android_stats/statsd_logging_helper.h"
 
+#include <cstdint>
 #include <string>
+#include <vector>
 
 #include "perfetto/base/build_config.h"
-#include "perfetto/base/compiler.h"
+#include "src/android_stats/perfetto_atoms.h"
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
     PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
@@ -27,8 +29,7 @@
 #include "src/android_internal/statsd_logging.h"       // nogncheck
 #endif
 
-namespace perfetto {
-namespace android_stats {
+namespace perfetto::android_stats {
 
 // Make sure we don't accidentally log on non-Android tree build. Note that even
 // removing this ifdef still doesn't make uploads work on OS_ANDROID.
@@ -75,5 +76,4 @@
                            const std::vector<std::string>&) {}
 #endif
 
-}  // namespace android_stats
-}  // namespace perfetto
+}  // namespace perfetto::android_stats
diff --git a/src/android_stats/statsd_logging_helper.h b/src/android_stats/statsd_logging_helper.h
index 5f0911f..0ba2d65 100644
--- a/src/android_stats/statsd_logging_helper.h
+++ b/src/android_stats/statsd_logging_helper.h
@@ -18,6 +18,7 @@
 #define SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
 
 #include <stdint.h>
+#include <optional>
 #include <string>
 #include <vector>
 
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 2ccd24e..e11a485 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -16,46 +16,47 @@
 
 #include "src/perfetto_cmd/perfetto_cmd.h"
 
-#include "perfetto/base/build_config.h"
-#include "perfetto/base/proc_utils.h"
-#include "perfetto/ext/base/scoped_file.h"
-#include "perfetto/ext/base/string_splitter.h"
-
 #include <fcntl.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <time.h>
 
-// For dup() (and _setmode() on windows).
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <fcntl.h>
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
+#include <algorithm>
+#include <array>
 #include <atomic>
 #include <chrono>
-#include <fstream>
+#include <cinttypes>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
 #include <iostream>
 #include <iterator>
+#include <memory>
 #include <mutex>
+#include <optional>
 #include <random>
-#include <sstream>
+#include <string>
 #include <thread>
+#include <utility>
+#include <vector>
 
+#include "perfetto/base/build_config.h"
 #include "perfetto/base/compiler.h"
 #include "perfetto/base/logging.h"
-#include "perfetto/base/time.h"
-#include "perfetto/ext/base/android_utils.h"
+#include "perfetto/base/proc_utils.h"         // IWYU pragma: keep
+#include "perfetto/ext/base/android_utils.h"  // IWYU pragma: keep
 #include "perfetto/ext/base/ctrl_c_handler.h"
 #include "perfetto/ext/base/file_utils.h"
-#include "perfetto/ext/base/getopt.h"
+#include "perfetto/ext/base/getopt.h"  // IWYU pragma: keep
 #include "perfetto/ext/base/no_destructor.h"
 #include "perfetto/ext/base/pipe.h"
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/string_splitter.h"
+#include "perfetto/ext/base/string_utils.h"
 #include "perfetto/ext/base/string_view.h"
-#include "perfetto/ext/base/temp_file.h"
+#include "perfetto/ext/base/thread_task_runner.h"
 #include "perfetto/ext/base/thread_utils.h"
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/ext/base/uuid.h"
@@ -64,11 +65,14 @@
 #include "perfetto/ext/traced/traced.h"
 #include "perfetto/ext/tracing/core/basic_types.h"
 #include "perfetto/ext/tracing/core/trace_packet.h"
-#include "perfetto/protozero/proto_utils.h"
-#include "perfetto/tracing/core/data_source_descriptor.h"
+#include "perfetto/ext/tracing/core/tracing_service.h"
+#include "perfetto/ext/tracing/ipc/consumer_ipc_client.h"
+#include "perfetto/tracing/core/flush_flags.h"
+#include "perfetto/tracing/core/forward_decls.h"
 #include "perfetto/tracing/core/trace_config.h"
-#include "perfetto/tracing/core/tracing_service_state.h"
 #include "perfetto/tracing/default_socket.h"
+#include "protos/perfetto/common/data_source_descriptor.gen.h"
+#include "src/android_stats/perfetto_atoms.h"
 #include "src/android_stats/statsd_logging_helper.h"
 #include "src/perfetto_cmd/bugreport_path.h"
 #include "src/perfetto_cmd/config.h"
@@ -81,6 +85,14 @@
 #include "protos/perfetto/common/tracing_service_state.gen.h"
 #include "protos/perfetto/common/track_event_descriptor.gen.h"
 
+// For dup() (and _setmode() on windows).
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
 namespace perfetto {
 namespace {
 
@@ -92,7 +104,7 @@
 class LoggingErrorReporter : public ErrorReporter {
  public:
   LoggingErrorReporter(std::string file_name, const char* config)
-      : file_name_(file_name), config_(config) {}
+      : file_name_(std::move(file_name)), config_(config) {}
 
   void AddError(size_t row,
                 size_t column,
@@ -1014,7 +1026,14 @@
     std::this_thread::sleep_for(std::chrono::milliseconds(dist(minstd)));
   }
 
-  if (trace_config_->trigger_config().trigger_timeout_ms() == 0) {
+  if (clone_tsid_) {
+    if (snapshot_trigger_name_.empty()) {
+      LogUploadEvent(PerfettoStatsdAtom::kCloneTraceBegin);
+    } else {
+      LogUploadEvent(PerfettoStatsdAtom::kCloneTriggerTraceBegin,
+                     snapshot_trigger_name_);
+    }
+  } else if (trace_config_->trigger_config().trigger_timeout_ms() == 0) {
     LogUploadEvent(PerfettoStatsdAtom::kTraceBegin);
   } else {
     LogUploadEvent(PerfettoStatsdAtom::kBackgroundTraceBegin);
@@ -1533,11 +1552,15 @@
   }
   if (observable_events.has_clone_trigger_hit()) {
     int64_t tsid = observable_events.clone_trigger_hit().tracing_session_id();
-    OnCloneSnapshotTriggerReceived(static_cast<TracingSessionID>(tsid));
+    std::string trigger_name =
+        observable_events.clone_trigger_hit().trigger_name();
+    OnCloneSnapshotTriggerReceived(static_cast<TracingSessionID>(tsid),
+                                   std::move(trigger_name));
   }
 }
 
-void PerfettoCmd::OnCloneSnapshotTriggerReceived(TracingSessionID tsid) {
+void PerfettoCmd::OnCloneSnapshotTriggerReceived(TracingSessionID tsid,
+                                                 std::string trigger_name) {
   std::string cmdline;
   cmdline.reserve(128);
   ArgsAppend(&cmdline, "perfetto");
@@ -1555,13 +1578,15 @@
   } else {
     PERFETTO_FATAL("Cannot use CLONE_SNAPSHOT with the current cmdline args");
   }
-  CloneSessionOnThread(tsid, cmdline, kSingleExtraThread, nullptr);
+  CloneSessionOnThread(tsid, cmdline, kSingleExtraThread,
+                       std::move(trigger_name), nullptr);
 }
 
 void PerfettoCmd::CloneSessionOnThread(
     TracingSessionID tsid,
     const std::string& cmdline,
     CloneThreadMode thread_mode,
+    std::string trigger_name,
     std::function<void()> on_clone_callback) {
   PERFETTO_DLOG("Creating snapshot for tracing session %" PRIu64, tsid);
 
@@ -1583,7 +1608,7 @@
   std::string trace_config_copy = trace_config_->SerializeAsString();
 
   snapshot_threads_.back().PostTask(
-      [tsid, cmdline, trace_config_copy, on_clone_callback] {
+      [tsid, cmdline, trace_config_copy, trigger_name, on_clone_callback] {
         int argc = 0;
         char* argv[32];
         // `splitter` needs to live on the stack for the whole scope as it owns
@@ -1595,6 +1620,7 @@
         }
         perfetto::PerfettoCmd cmd;
         cmd.snapshot_config_ = std::move(trace_config_copy);
+        cmd.snapshot_trigger_name_ = std::move(trigger_name);
         cmd.on_session_cloned_ = on_clone_callback;
         auto cmdline_res = cmd.ParseCmdlineAndMaybeDaemonize(argc, argv);
         PERFETTO_CHECK(!cmdline_res.has_value());  // No daemonization expected.
@@ -1686,7 +1712,7 @@
     ArgsAppend(&cmdline, "--clone-for-bugreport");
     ArgsAppend(&cmdline, "--out");
     ArgsAppend(&cmdline, out_path);
-    CloneSessionOnThread(it->tsid, cmdline, kNewThreadPerRequest, sync_fn);
+    CloneSessionOnThread(it->tsid, cmdline, kNewThreadPerRequest, "", sync_fn);
   }  // for(sessions)
 
   PERFETTO_DLOG("Issuing %zu CloneSession requests", num_sessions);
@@ -1720,6 +1746,15 @@
   android_stats::MaybeLogUploadEvent(atom, uuid.lsb(), uuid.msb());
 }
 
+void PerfettoCmd::LogUploadEvent(PerfettoStatsdAtom atom,
+                                 const std::string& trigger_name) {
+  if (!statsd_logging_)
+    return;
+  base::Uuid uuid(uuid_);
+  android_stats::MaybeLogUploadEvent(atom, uuid.lsb(), uuid.msb(),
+                                     trigger_name);
+}
+
 void PerfettoCmd::LogTriggerEvents(
     PerfettoTriggerAtom atom,
     const std::vector<std::string>& trigger_names) {
diff --git a/src/perfetto_cmd/perfetto_cmd.h b/src/perfetto_cmd/perfetto_cmd.h
index 844afaf..160a701 100644
--- a/src/perfetto_cmd/perfetto_cmd.h
+++ b/src/perfetto_cmd/perfetto_cmd.h
@@ -17,8 +17,7 @@
 #ifndef SRC_PERFETTO_CMD_PERFETTO_CMD_H_
 #define SRC_PERFETTO_CMD_PERFETTO_CMD_H_
 
-#include <time.h>
-
+#include <cstdint>
 #include <functional>
 #include <list>
 #include <memory>
@@ -32,9 +31,12 @@
 #include "perfetto/ext/base/scoped_file.h"
 #include "perfetto/ext/base/thread_task_runner.h"
 #include "perfetto/ext/base/unix_task_runner.h"
+#include "perfetto/ext/base/uuid.h"
 #include "perfetto/ext/base/weak_ptr.h"
+#include "perfetto/ext/tracing/core/basic_types.h"
 #include "perfetto/ext/tracing/core/consumer.h"
 #include "perfetto/ext/tracing/ipc/consumer_ipc_client.h"
+#include "perfetto/tracing/core/forward_decls.h"
 #include "src/android_stats/perfetto_atoms.h"
 #include "src/perfetto_cmd/packet_writer.h"
 
@@ -86,6 +88,7 @@
   void CloneSessionOnThread(TracingSessionID,
                             const std::string& cmdline,  // \0 separated.
                             CloneThreadMode,
+                            std::string clone_trigger_name,
                             std::function<void()> on_clone_callback);
   void OnTimeout();
   bool is_detach() const { return !detach_key_.empty(); }
@@ -126,7 +129,8 @@
   // will have no effect.
   void NotifyBgProcessPipe(BgProcessStatus status);
 
-  void OnCloneSnapshotTriggerReceived(TracingSessionID);
+  void OnCloneSnapshotTriggerReceived(TracingSessionID,
+                                      std::string trigger_name);
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
   static base::ScopedFile CreateUnlinkedTmpFile();
@@ -135,6 +139,7 @@
   void ReportTraceToAndroidFrameworkOrCrash();
 #endif
   void LogUploadEvent(PerfettoStatsdAtom atom);
+  void LogUploadEvent(PerfettoStatsdAtom atom, const std::string& trigger_name);
   void LogTriggerEvents(PerfettoTriggerAtom atom,
                         const std::vector<std::string>& trigger_names);
 
@@ -185,6 +190,7 @@
   std::list<base::ThreadTaskRunner> snapshot_threads_;
   int snapshot_count_ = 0;
   std::string snapshot_config_;
+  std::string snapshot_trigger_name_;
 
   base::WeakPtrFactory<PerfettoCmd> weak_factory_{this};
 };
diff --git a/src/trace_processor/importers/common/process_tracker.cc b/src/trace_processor/importers/common/process_tracker.cc
index 3fc95fc..e292801 100644
--- a/src/trace_processor/importers/common/process_tracker.cc
+++ b/src/trace_processor/importers/common/process_tracker.cc
@@ -356,6 +356,17 @@
   UniquePid upid = GetOrCreateProcess(pid);
   auto* process_table = context_->storage->mutable_process_table();
 
+  // If we both know the previous and current parent pid and the two are not
+  // matching, we must have died and restarted: create a new process.
+  if (pupid) {
+    std::optional<UniquePid> prev_parent_upid =
+        process_table->parent_upid()[upid];
+    if (prev_parent_upid && prev_parent_upid != pupid) {
+      upid = StartNewProcess(std::nullopt, ppid, pid, kNullStringId,
+                             ThreadNamePriority::kOther);
+    }
+  }
+
   StringId proc_name_id = context_->storage->InternString(name);
   process_table->mutable_name()->Set(upid, proc_name_id);
   process_table->mutable_cmdline()->Set(
diff --git a/src/trace_redaction/main.cc b/src/trace_redaction/main.cc
index 296f12f..78bf3d0 100644
--- a/src/trace_redaction/main.cc
+++ b/src/trace_redaction/main.cc
@@ -84,10 +84,18 @@
 
   auto* redact_ftrace_events = redactor.emplace_transform<RedactFtraceEvent>();
   redact_ftrace_events
-      ->emplace_back<RedactTaskNewTask::kFieldId, RedactTaskNewTask>();
-  redact_ftrace_events
       ->emplace_back<RemoveProcessFreeComm::kFieldId, RemoveProcessFreeComm>();
 
+  // By default, the comm value is cleared. However, when thread merging is
+  // enabled (kTaskNewtaskFieldNumber + ThreadMergeDropField), the event is
+  // dropped, meaning that this primitive was effectivly a no-op. This primitive
+  // remains so that removing thread merging won't leak thread names via new
+  // task events.
+  auto* redact_new_task =
+      redact_ftrace_events
+          ->emplace_back<RedactTaskNewTask::kFieldId, RedactTaskNewTask>();
+  redact_new_task->emplace_back<ClearComms>();
+
   // This set of transformations will change pids. This will break the
   // connections between pids and the timeline (the synth threads are not in the
   // timeline). If a transformation uses the timeline, it must be before this
diff --git a/src/trace_redaction/redact_ftrace_event.h b/src/trace_redaction/redact_ftrace_event.h
index 9de6cc6..68aff05 100644
--- a/src/trace_redaction/redact_ftrace_event.h
+++ b/src/trace_redaction/redact_ftrace_event.h
@@ -57,8 +57,12 @@
   // Add a new redaction. T must extend FtraceEventRedaction. This relies on the
   // honor system; no more than one redaction can be mapped to a field.
   template <uint32_t field_id, class T>
-  void emplace_back() {
-    redactions_.Insert(field_id, std::make_unique<T>());
+  T* emplace_back() {
+    auto ptr = std::make_unique<T>();
+    T* raw_ptr = ptr.get();
+
+    redactions_.Insert(field_id, std::move(ptr));
+    return raw_ptr;
   }
 
  private:
diff --git a/src/trace_redaction/redact_task_newtask.cc b/src/trace_redaction/redact_task_newtask.cc
index fb0cfe8..7a0fbeb 100644
--- a/src/trace_redaction/redact_task_newtask.cc
+++ b/src/trace_redaction/redact_task_newtask.cc
@@ -16,28 +16,15 @@
 
 #include "src/trace_redaction/redact_task_newtask.h"
 
-#include "src/trace_redaction/proto_util.h"
-
 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
+#include "src/trace_processor/util/status_macros.h"
 
 namespace perfetto::trace_redaction {
 
 namespace {
 
-// TODO(vaage): Merge with RedactComm in redact_sched_switch.cc.
-protozero::ConstChars RedactComm(const Context& context,
-                                 uint64_t ts,
-                                 int32_t pid,
-                                 protozero::ConstChars comm) {
-  if (context.timeline->PidConnectsToUid(ts, pid, *context.package_uid)) {
-    return comm;
-  }
-
-  return {};
-}
-
 }  // namespace
 // Redact sched switch trace events in an ftrace event bundle:
 //
@@ -56,9 +43,11 @@
 // equal to "event.task_newtask.pid" (a thread cannot start itself).
 base::Status RedactTaskNewTask::Redact(
     const Context& context,
-    const protos::pbzero::FtraceEventBundle::Decoder&,
+    const protos::pbzero::FtraceEventBundle::Decoder& bundle,
     protozero::ProtoDecoder& event,
     protos::pbzero::FtraceEvent* event_message) const {
+  PERFETTO_DCHECK(transform_);
+
   if (!context.package_uid.has_value()) {
     return base::ErrStatus("RedactTaskNewTask: missing package uid");
   }
@@ -68,45 +57,41 @@
   }
 
   // The timestamp is needed to do the timeline look-up. If the packet has no
-  // timestamp, don't add the sched switch event. This is the safest option.
-  auto timestamp =
+  // timestamp, don't add the sched switch event.
+  auto timestamp_field =
       event.FindField(protos::pbzero::FtraceEvent::kTimestampFieldNumber);
-  if (!timestamp.valid()) {
-    return base::OkStatus();
-  }
-
-  auto new_task =
+  auto new_task_field =
       event.FindField(protos::pbzero::FtraceEvent::kTaskNewtaskFieldNumber);
-  if (!new_task.valid()) {
+
+  if (!timestamp_field.valid() || !new_task_field.valid()) {
     return base::ErrStatus(
-        "RedactTaskNewTask: was used for unsupported field type");
+        "RedactTaskNewTask: missing required FtraceEvent field.");
   }
 
-  protozero::ProtoDecoder new_task_decoder(new_task.as_bytes());
+  protos::pbzero::TaskNewtaskFtraceEvent::Decoder new_task(
+      new_task_field.as_bytes());
 
-  auto pid = new_task_decoder.FindField(
-      protos::pbzero::TaskNewtaskFtraceEvent::kPidFieldNumber);
-
-  if (!pid.valid()) {
-    return base::OkStatus();
+  // There are only four fields in a new task event. Since two of them can
+  // change, it is easier to work with them directly.
+  if (!new_task.has_pid() || !new_task.has_comm() ||
+      !new_task.has_clone_flags() || !new_task.has_oom_score_adj()) {
+    return base::ErrStatus(
+        "RedactTaskNewTask: missing required TaskNewtaskFtraceEvent field.");
   }
 
-  // Avoid making the message until we know that we have prev and next pids.
+  auto pid = new_task.pid();
+  auto comm = new_task.comm().ToStdString();
+
+  auto cpu = static_cast<int32_t>(bundle.cpu());
+
+  RETURN_IF_ERROR(transform_->Transform(context, timestamp_field.as_uint64(),
+                                        cpu, &pid, &comm));
+
   auto* new_task_message = event_message->set_task_newtask();
-
-  for (auto field = new_task_decoder.ReadField(); field.valid();
-       field = new_task_decoder.ReadField()) {
-    // Perfetto view (ui.perfetto.dev) crashes if the comm value is missing.
-    // To work around this, the comm value is replaced with an empty string.
-    // This appears to work.
-    if (field.id() ==
-        protos::pbzero::TaskNewtaskFtraceEvent::kCommFieldNumber) {
-      new_task_message->set_comm(RedactComm(context, timestamp.as_uint64(),
-                                            pid.as_int32(), field.as_string()));
-    } else {
-      proto_util::AppendField(field, new_task_message);
-    }
-  }
+  new_task_message->set_pid(pid);
+  new_task_message->set_comm(comm);
+  new_task_message->set_clone_flags(new_task.clone_flags());
+  new_task_message->set_oom_score_adj(new_task.oom_score_adj());
 
   return base::OkStatus();
 }
diff --git a/src/trace_redaction/redact_task_newtask.h b/src/trace_redaction/redact_task_newtask.h
index 51c1124..5b589fc 100644
--- a/src/trace_redaction/redact_task_newtask.h
+++ b/src/trace_redaction/redact_task_newtask.h
@@ -18,6 +18,7 @@
 #define SRC_TRACE_REDACTION_REDACT_TASK_NEWTASK_H_
 
 #include "src/trace_redaction/redact_ftrace_event.h"
+#include "src/trace_redaction/redact_sched_switch.h"
 #include "src/trace_redaction/trace_redaction_framework.h"
 
 namespace perfetto::trace_redaction {
@@ -34,6 +35,14 @@
       const protos::pbzero::FtraceEventBundle::Decoder& bundle,
       protozero::ProtoDecoder& event,
       protos::pbzero::FtraceEvent* event_message) const override;
+
+  template <class Transform>
+  void emplace_back() {
+    transform_ = std::make_unique<Transform>();
+  }
+
+ public:
+  std::unique_ptr<SchedSwitchTransform> transform_;
 };
 
 }  // namespace perfetto::trace_redaction
diff --git a/src/trace_redaction/redact_task_newtask_unittest.cc b/src/trace_redaction/redact_task_newtask_unittest.cc
index 33886f6..11b1405 100644
--- a/src/trace_redaction/redact_task_newtask_unittest.cc
+++ b/src/trace_redaction/redact_task_newtask_unittest.cc
@@ -16,19 +16,21 @@
 
 #include "src/trace_redaction/redact_task_newtask.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
-#include "protos/perfetto/trace/ftrace/task.gen.h"
+#include "src/base/test/status_matchers.h"
 #include "test/gtest_and_gmock.h"
 
 #include "protos/perfetto/trace/ftrace/ftrace_event.gen.h"
 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.gen.h"
-#include "protos/perfetto/trace/ftrace/sched.gen.h"
+#include "protos/perfetto/trace/ftrace/task.gen.h"
 #include "protos/perfetto/trace/trace.gen.h"
 #include "protos/perfetto/trace/trace_packet.gen.h"
 
 namespace perfetto::trace_redaction {
 
 namespace {
+constexpr uint64_t kCpu = 1;
+
 constexpr uint64_t kUidA = 1;
 constexpr uint64_t kUidB = 2;
 
@@ -44,19 +46,23 @@
 class RedactTaskNewTaskTest : public testing::Test {
  protected:
   void SetUp() override {
-    auto* event = bundle_.add_event();
+    bundle_.set_cpu(kCpu);
 
+    auto* event = bundle_.add_event();
     event->set_timestamp(123456789);
     event->set_pid(kPidA);
 
     auto* new_task = event->mutable_task_newtask();
+    new_task->set_clone_flags(0);
     new_task->set_comm(std::string(kCommA));
+    new_task->set_oom_score_adj(0);
     new_task->set_pid(kPidA);
   }
 
   base::Status Redact(const Context& context,
                       protos::pbzero::FtraceEvent* event_message) {
     RedactTaskNewTask redact;
+    redact.emplace_back<ClearComms>();
 
     auto bundle_str = bundle_.SerializeAsString();
     protos::pbzero::FtraceEventBundle::Decoder bundle_decoder(bundle_str);
@@ -93,8 +99,6 @@
 };
 
 TEST_F(RedactTaskNewTaskTest, RejectMissingPackageUid) {
-  RedactTaskNewTask redact;
-
   Context context;
   context.timeline = std::make_unique<ProcessThreadTimeline>();
 
@@ -106,8 +110,6 @@
 }
 
 TEST_F(RedactTaskNewTaskTest, RejectMissingTimeline) {
-  RedactTaskNewTask redact;
-
   Context context;
   context.package_uid = kUidA;
 
@@ -119,8 +121,6 @@
 }
 
 TEST_F(RedactTaskNewTaskTest, PidInPackageKeepsComm) {
-  RedactTaskNewTask redact;
-
   // Because Uid A is the target, when Pid A starts (new task event), it should
   // keep its comm value.
   Context context;
@@ -130,8 +130,7 @@
   protos::pbzero::FtraceEvent::Decoder event_decoder(event_string());
   protozero::HeapBuffered<protos::pbzero::FtraceEvent> event_message;
 
-  auto result = Redact(context, event_message.get());
-  ASSERT_TRUE(result.ok());
+  ASSERT_OK(Redact(context, event_message.get()));
 
   protos::gen::FtraceEvent redacted_event;
   redacted_event.ParseFromString(event_message.SerializeAsString());
@@ -142,8 +141,6 @@
 }
 
 TEST_F(RedactTaskNewTaskTest, PidOutsidePackageLosesComm) {
-  RedactTaskNewTask redact;
-
   // Because Uid B is the target, when Pid A starts (new task event), it should
   // lose its comm value.
   Context context;
@@ -153,8 +150,7 @@
   protos::pbzero::FtraceEvent::Decoder event_decoder(event_string());
   protozero::HeapBuffered<protos::pbzero::FtraceEvent> event_message;
 
-  auto result = Redact(context, event_message.get());
-  ASSERT_TRUE(result.ok());
+  ASSERT_OK(Redact(context, event_message.get()));
 
   protos::gen::FtraceEvent redacted_event;
   redacted_event.ParseFromString(event_message.SerializeAsString());
diff --git a/src/traced/probes/ftrace/cpu_reader.cc b/src/traced/probes/ftrace/cpu_reader.cc
index 66b9b1b..4045978 100644
--- a/src/traced/probes/ftrace/cpu_reader.cc
+++ b/src/traced/probes/ftrace/cpu_reader.cc
@@ -869,6 +869,9 @@
     case kDevId64ToUint64:
       ReadDevId<uint64_t>(field_start, field_id, message, metadata);
       return true;
+    case kFtraceSymAddr32ToUint64:
+      ReadSymbolAddr<uint32_t>(field_start, field_id, message, metadata);
+      return true;
     case kFtraceSymAddr64ToUint64:
       ReadSymbolAddr<uint64_t>(field_start, field_id, message, metadata);
       return true;
diff --git a/src/traced/probes/ftrace/event_info_constants.cc b/src/traced/probes/ftrace/event_info_constants.cc
index 37f9c77..4a0d08f 100644
--- a/src/traced/probes/ftrace/event_info_constants.cc
+++ b/src/traced/probes/ftrace/event_info_constants.cc
@@ -106,6 +106,8 @@
     *out = kBoolToUint64;
   } else if (ftrace == kFtraceDataLoc && proto == ProtoSchemaType::kString) {
     *out = kDataLocToString;
+  } else if (ftrace == kFtraceSymAddr32 && proto == ProtoSchemaType::kUint64) {
+    *out = kFtraceSymAddr32ToUint64;
   } else if (ftrace == kFtraceSymAddr64 && proto == ProtoSchemaType::kUint64) {
     *out = kFtraceSymAddr64ToUint64;
   } else {
diff --git a/src/traced/probes/ftrace/event_info_constants.h b/src/traced/probes/ftrace/event_info_constants.h
index 0283f12..cce144f 100644
--- a/src/traced/probes/ftrace/event_info_constants.h
+++ b/src/traced/probes/ftrace/event_info_constants.h
@@ -48,6 +48,7 @@
   kFtraceDevId32,
   kFtraceDevId64,
   kFtraceDataLoc,
+  kFtraceSymAddr32,
   kFtraceSymAddr64,
 };
 
@@ -84,6 +85,7 @@
   kDevId32ToUint64,
   kDevId64ToUint64,
   kDataLocToString,
+  kFtraceSymAddr32ToUint64,
   kFtraceSymAddr64ToUint64,
 };
 
@@ -127,6 +129,7 @@
       return "devid64";
     case kFtraceDataLoc:
       return "__data_loc";
+    case kFtraceSymAddr32:
     case kFtraceSymAddr64:
       return "void*";
     case kInvalidFtraceFieldType:
diff --git a/src/traced/probes/ftrace/proto_translation_table.cc b/src/traced/probes/ftrace/proto_translation_table.cc
index 9dcde14..7e9092e 100644
--- a/src/traced/probes/ftrace/proto_translation_table.cc
+++ b/src/traced/probes/ftrace/proto_translation_table.cc
@@ -239,6 +239,7 @@
     case kFtraceUint64:
     case kFtraceInode32:
     case kFtraceInode64:
+    case kFtraceSymAddr32:
     case kFtraceSymAddr64:
       *proto_type = ProtoSchemaType::kUint64;
       *proto_field_id = GenericFtraceEvent::Field::kUintValueFieldNumber;
@@ -310,13 +311,16 @@
     return true;
   }
 
-  // Kernel addresses that need symbolization via kallsyms. Only 64-bit kernels
-  // are supported for now. 32-bit kernels seems to be going away.
-  if ((base::StartsWith(type_and_name, "void*") ||
-       base::StartsWith(type_and_name, "void *")) &&
-      size == 8) {
-    *out = kFtraceSymAddr64;
-    return true;
+  // Kernel addresses that need symbolization via kallsyms.
+  if (base::StartsWith(type_and_name, "void*") ||
+      base::StartsWith(type_and_name, "void *")) {
+    if (size == 4) {
+      *out = kFtraceSymAddr32;
+      return true;
+    } else if (size == 8) {
+      *out = kFtraceSymAddr64;
+      return true;
+    }
   }
 
   // Variable length strings: "char foo" + size: 0 (as in 'print').
diff --git a/src/tracing/service/tracing_service_impl.cc b/src/tracing/service/tracing_service_impl.cc
index d667767..6631d68 100644
--- a/src/tracing/service/tracing_service_impl.cc
+++ b/src/tracing/service/tracing_service_impl.cc
@@ -24,6 +24,7 @@
 #include <limits>
 #include <optional>
 #include <regex>
+#include <string>
 #include <unordered_set>
 #include "perfetto/base/time.h"
 #include "perfetto/ext/tracing/core/client_identity.h"
@@ -1689,13 +1690,14 @@
               tracing_session.config, tracing_session.trace_uuid,
               PerfettoStatsdAtom::kTracedTriggerCloneSnapshot, iter->name());
           task_runner_->PostDelayedTask(
-              [weak_this, tsid] {
+              [weak_this, tsid, trigger_name = iter->name()] {
                 if (!weak_this)
                   return;
                 auto* tsess = weak_this->GetTracingSession(tsid);
                 if (!tsess || !tsess->consumer_maybe_null)
                   return;
-                tsess->consumer_maybe_null->NotifyCloneSnapshotTrigger();
+                tsess->consumer_maybe_null->NotifyCloneSnapshotTrigger(
+                    trigger_name);
               },
               iter->stop_delay_ms());
           break;
@@ -4265,13 +4267,15 @@
   observable_events->set_all_data_sources_started(true);
 }
 
-void TracingServiceImpl::ConsumerEndpointImpl::NotifyCloneSnapshotTrigger() {
+void TracingServiceImpl::ConsumerEndpointImpl::NotifyCloneSnapshotTrigger(
+    const std::string& trigger_name) {
   if (!(observable_events_mask_ & ObservableEvents::TYPE_CLONE_TRIGGER_HIT)) {
     return;
   }
   auto* observable_events = AddObservableEvents();
   auto* clone_trig = observable_events->mutable_clone_trigger_hit();
   clone_trig->set_tracing_session_id(static_cast<int64_t>(tracing_session_id_));
+  clone_trig->set_trigger_name(trigger_name);
 }
 
 ObservableEvents*
diff --git a/src/tracing/service/tracing_service_impl.h b/src/tracing/service/tracing_service_impl.h
index 9fa84fe..1dbcbe6 100644
--- a/src/tracing/service/tracing_service_impl.h
+++ b/src/tracing/service/tracing_service_impl.h
@@ -32,6 +32,7 @@
 #include "perfetto/base/time.h"
 #include "perfetto/ext/base/circular_queue.h"
 #include "perfetto/ext/base/periodic_task.h"
+#include "perfetto/ext/base/string_view.h"
 #include "perfetto/ext/base/uuid.h"
 #include "perfetto/ext/base/weak_ptr.h"
 #include "perfetto/ext/tracing/core/basic_types.h"
@@ -211,7 +212,7 @@
     ~ConsumerEndpointImpl() override;
 
     void NotifyOnTracingDisabled(const std::string& error);
-    void NotifyCloneSnapshotTrigger();
+    void NotifyCloneSnapshotTrigger(const std::string& trigger_name);
 
     // TracingService::ConsumerEndpoint implementation.
     void EnableTracing(const TraceConfig&, base::ScopedFile) override;
diff --git a/test/trace_processor/diff_tests/parser/process_tracking/process_tracking_exec.py b/test/trace_processor/diff_tests/parser/process_tracking/process_tracking_exec.py
index a706d7e..83e1034 100644
--- a/test/trace_processor/diff_tests/parser/process_tracking/process_tracking_exec.py
+++ b/test/trace_processor/diff_tests/parser/process_tracking/process_tracking_exec.py
@@ -22,24 +22,25 @@
 
 trace = synth_common.create_trace()
 
-# Create a parent process which  will be forked below.
+# Create a parent process which will be forked below.
 trace.add_packet(ts=1)
 trace.add_process(10, 0, "parent")
 
-# Fork off the new process and then kill it 5ns later.
+# Fork the process into a child.
 trace.add_ftrace_packet(0)
 trace.add_newtask(ts=15, tid=10, new_tid=11, new_comm='child', flags=0)
 trace.add_sched(ts=16, prev_pid=10, next_pid=11, next_comm='child')
 
-# Create a parent process which  will be forked below.
+# Scrape event for the forked process.
 trace.add_packet(ts=20)
-trace.add_process(11, 0, "child_process")
+trace.add_process(11, 10, "child_process")
 
+# Rename of the main thread of forked process.
 trace.add_ftrace_packet(0)
 trace.add_rename(
     ts=25, tid=11, old_comm='child', new_comm='true_name', oom_score_adj=1000)
 
-# Create a parent process which  will be forked below.
+# Scrape of the forked process.
 trace.add_packet(ts=30)
 trace.add_process(11, 10, "true_process_name")
 
diff --git a/test/trace_processor/diff_tests/parser/process_tracking/synth_process_tracking.py b/test/trace_processor/diff_tests/parser/process_tracking/synth_process_tracking.py
index 68641ad..19bf834 100644
--- a/test/trace_processor/diff_tests/parser/process_tracking/synth_process_tracking.py
+++ b/test/trace_processor/diff_tests/parser/process_tracking/synth_process_tracking.py
@@ -90,7 +90,7 @@
     ts=28, prev_pid=32, next_pid=40, prev_comm='p3-t2', next_comm='p4-t0')
 
 trace.add_packet(ts=29)
-trace.add_process(40, 0, "process_4")
+trace.add_process(40, 30, "process_4")
 
 # And now, this new process starts a new thread that recycles TID=31 (previously
 # used as p3-t1, now becomes p4-t1).
diff --git a/tools/install-build-deps b/tools/install-build-deps
index 31972d4..62d1ac6 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -185,6 +185,11 @@
     # Keep in sync with Chromium's //third_party/protobuf.
     Dependency(
         'buildtools/protobuf',
+        # If you revert the below version back to an earlier version of
+        # protobuf, make sure to revert the changes to
+        # //gn/standalone/protoc.py as well.
+        #
+        # This comment can be removed with protobuf is next upreved.
         'https://chromium.googlesource.com/external/github.com/protocolbuffers/protobuf.git',
         'f0dc78d7e6e331b8c6bb2d5283e06aa26883ca7c',  # refs/tags/v21.12
         'all',