Merge "tp: fix tracking when process reuse happens before ftrace starts" 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/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/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').