Trace Redaction - Remove comm values from all process free events

Process free events contain a pid and a comm. The timeline uses an
exclusive end bound, so it is not possible to use the event's
timestamp to see of the pid belongs to the package. Instead of using
a fudge value (e.g. time - 1), all process free events will lose their
comm values.

Bug: 318576499

Change-Id: Iceb2adb7f1618a46fe47c8dc5f44b6f68f73701d
diff --git a/Android.bp b/Android.bp
index 1cf094b..43d2027 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12871,6 +12871,7 @@
         "src/trace_redaction/proto_util.cc",
         "src/trace_redaction/prune_package_list.cc",
         "src/trace_redaction/redact_ftrace_event.cc",
+        "src/trace_redaction/redact_process_free.cc",
         "src/trace_redaction/redact_sched_switch.cc",
         "src/trace_redaction/redact_task_newtask.cc",
         "src/trace_redaction/scrub_ftrace_events.cc",
@@ -12895,6 +12896,7 @@
         "src/trace_redaction/process_thread_timeline_unittest.cc",
         "src/trace_redaction/proto_util_unittest.cc",
         "src/trace_redaction/prune_package_list_unittest.cc",
+        "src/trace_redaction/redact_process_free_unittest.cc",
         "src/trace_redaction/redact_sched_switch_unittest.cc",
         "src/trace_redaction/redact_task_newtask_unittest.cc",
     ],
diff --git a/src/trace_redaction/BUILD.gn b/src/trace_redaction/BUILD.gn
index bf254c9..e876fac 100644
--- a/src/trace_redaction/BUILD.gn
+++ b/src/trace_redaction/BUILD.gn
@@ -54,6 +54,8 @@
     "prune_package_list.h",
     "redact_ftrace_event.cc",
     "redact_ftrace_event.h",
+    "redact_process_free.cc",
+    "redact_process_free.h",
     "redact_sched_switch.cc",
     "redact_sched_switch.h",
     "redact_task_newtask.cc",
@@ -124,6 +126,7 @@
     "process_thread_timeline_unittest.cc",
     "proto_util_unittest.cc",
     "prune_package_list_unittest.cc",
+    "redact_process_free_unittest.cc",
     "redact_sched_switch_unittest.cc",
     "redact_task_newtask_unittest.cc",
   ]
diff --git a/src/trace_redaction/main.cc b/src/trace_redaction/main.cc
index a8a1cdc..003ad78 100644
--- a/src/trace_redaction/main.cc
+++ b/src/trace_redaction/main.cc
@@ -27,6 +27,7 @@
 #include "src/trace_redaction/populate_allow_lists.h"
 #include "src/trace_redaction/prune_package_list.h"
 #include "src/trace_redaction/redact_ftrace_event.h"
+#include "src/trace_redaction/redact_process_free.h"
 #include "src/trace_redaction/redact_sched_switch.h"
 #include "src/trace_redaction/redact_task_newtask.h"
 #include "src/trace_redaction/scrub_ftrace_events.h"
@@ -72,6 +73,7 @@
   auto* redact_ftrace_events = redactor.emplace_transform<RedactFtraceEvent>();
   redact_ftrace_events->emplace_back<RedactSchedSwitch>();
   redact_ftrace_events->emplace_back<RedactTaskNewTask>();
+  redact_ftrace_events->emplace_back<RedactProcessFree>();
 
   Context context;
   context.package_name = package_name;
diff --git a/src/trace_redaction/redact_process_free.cc b/src/trace_redaction/redact_process_free.cc
new file mode 100644
index 0000000..654b7b2
--- /dev/null
+++ b/src/trace_redaction/redact_process_free.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_redaction/redact_process_free.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/sched.pbzero.h"
+
+namespace perfetto::trace_redaction {
+
+// Redact sched_process_free events.
+//
+//  event {
+//    timestamp: 6702094703928940
+//    pid: 10
+//    sched_process_free {
+//      comm: "sh"
+//      pid: 7973
+//      prio: 120
+//    }
+//  }
+//
+// In the above message, it should be noted that "event.pid" will not be
+// equal to "event.sched_process_free.pid".
+//
+// The timeline treats "start" as inclusive and "end" as exclusive. This means
+// no pid will connect to the target package at a process free event. Because
+// of this, the timeline is not needed.
+RedactProcessFree::RedactProcessFree()
+    : FtraceEventRedaction(
+          protos::pbzero::FtraceEvent::kSchedProcessFreeFieldNumber) {}
+
+base::Status RedactProcessFree::Redact(
+    const Context&,
+    const protos::pbzero::FtraceEvent::Decoder&,
+    protozero::ConstBytes bytes,
+    protos::pbzero::FtraceEvent* event_message) const {
+  protos::pbzero::SchedProcessFreeFtraceEvent::Decoder process_free(bytes);
+
+  // There must be pid. If there's no pid, dropping the event is the safest
+  // option.
+  if (!process_free.has_pid()) {
+    return base::OkStatus();
+  }
+
+  // Avoid making the message until we know that we have prev and next pids.
+  auto* process_free_message = event_message->set_sched_process_free();
+
+  // To read the fields, move the read head back to the start.
+  process_free.Reset();
+
+  for (auto field = process_free.ReadField(); field.valid();
+       field = process_free.ReadField()) {
+    if (field.id() !=
+        protos::pbzero::SchedProcessFreeFtraceEvent::kCommFieldNumber) {
+      proto_util::AppendField(field, process_free_message);
+    }
+  }
+
+  return base::OkStatus();
+}
+
+}  // namespace perfetto::trace_redaction
diff --git a/src/trace_redaction/redact_process_free.h b/src/trace_redaction/redact_process_free.h
new file mode 100644
index 0000000..f14fee2
--- /dev/null
+++ b/src/trace_redaction/redact_process_free.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_REDACTION_REDACT_PROCESS_FREE_H_
+#define SRC_TRACE_REDACTION_REDACT_PROCESS_FREE_H_
+
+#include "src/trace_redaction/redact_ftrace_event.h"
+#include "src/trace_redaction/trace_redaction_framework.h"
+
+namespace perfetto::trace_redaction {
+
+// Goes through ftrace events and conditonally removes the comm values from
+// process free events.
+class RedactProcessFree : public FtraceEventRedaction {
+ public:
+  RedactProcessFree();
+
+  base::Status Redact(
+      const Context& context,
+      const protos::pbzero::FtraceEvent::Decoder& event,
+      protozero::ConstBytes bytes,
+      protos::pbzero::FtraceEvent* event_message) const override;
+};
+
+}  // namespace perfetto::trace_redaction
+
+#endif  // SRC_TRACE_REDACTION_REDACT_PROCESS_FREE_H_
diff --git a/src/trace_redaction/redact_process_free_unittest.cc b/src/trace_redaction/redact_process_free_unittest.cc
new file mode 100644
index 0000000..ee119ca
--- /dev/null
+++ b/src/trace_redaction/redact_process_free_unittest.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_redaction/redact_process_free.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "src/base/test/status_matchers.h"
+#include "src/trace_redaction/trace_redaction_framework.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/trace.gen.h"
+#include "protos/perfetto/trace/trace_packet.gen.h"
+
+namespace perfetto::trace_redaction {
+
+class RedactProcessFreeTest : public testing::Test {};
+
+TEST_F(RedactProcessFreeTest, ClearsComm) {
+  protos::gen::FtraceEvent source_event;
+  source_event.set_timestamp(123456789);
+  source_event.set_pid(10);
+
+  auto* process_free = source_event.mutable_sched_process_free();
+  process_free->set_comm("comm-a");
+  process_free->set_pid(11);
+
+  RedactProcessFree redact;
+  Context context;
+
+  protos::pbzero::FtraceEvent::Decoder event_decoder(
+      source_event.SerializeAsString());
+  protozero::HeapBuffered<protos::pbzero::FtraceEvent> event_message;
+
+  auto result =
+      redact.Redact(context, event_decoder, event_decoder.sched_switch(),
+                    event_message.get());
+  ASSERT_OK(result) << result.c_message();
+
+  protos::gen::FtraceEvent redacted_event;
+  redacted_event.ParseFromString(event_message.SerializeAsString());
+
+  // No process free event should have been added to the ftrace event.
+  ASSERT_FALSE(redacted_event.has_sched_process_free());
+}
+
+// Even if there is no pid in the process free event, the process free event
+// should still exist but no comm value should be present.
+TEST_F(RedactProcessFreeTest, NoPidClearsEvent) {
+  protos::gen::FtraceEvent source_event;
+  source_event.set_timestamp(123456789);
+  source_event.set_pid(10);
+
+  // Don't add a pid. This should stop the process free event from being added
+  // to the event message.
+  auto* process_free = source_event.mutable_sched_process_free();
+  process_free->set_comm("comm-a");
+
+  RedactProcessFree redact;
+  Context context;
+
+  protos::pbzero::FtraceEvent::Decoder event_decoder(
+      source_event.SerializeAsString());
+  protozero::HeapBuffered<protos::pbzero::FtraceEvent> event_message;
+
+  // Even if the process free event has been dropped, there should be no
+  // resulting error.
+  auto result =
+      redact.Redact(context, event_decoder, event_decoder.sched_switch(),
+                    event_message.get());
+  ASSERT_OK(result) << result.c_message();
+
+  protos::gen::FtraceEvent redacted_event;
+  redacted_event.ParseFromString(event_message.SerializeAsString());
+
+  ASSERT_FALSE(redacted_event.has_sched_process_free());
+}
+
+}  // namespace perfetto::trace_redaction