aboutsummaryrefslogtreecommitdiff
path: root/src/trace_redaction/remap_scheduling_events.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/trace_redaction/remap_scheduling_events.cc')
-rw-r--r--src/trace_redaction/remap_scheduling_events.cc261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/trace_redaction/remap_scheduling_events.cc b/src/trace_redaction/remap_scheduling_events.cc
new file mode 100644
index 000000000..4817f1972
--- /dev/null
+++ b/src/trace_redaction/remap_scheduling_events.cc
@@ -0,0 +1,261 @@
+/*
+ * 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/remap_scheduling_events.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 {
+
+namespace {
+int32_t RemapPid(const Context& context,
+ uint64_t timestamp,
+ uint32_t cpu,
+ int32_t pid) {
+ PERFETTO_DCHECK(context.package_uid.value());
+ PERFETTO_DCHECK(cpu < context.synthetic_threads->tids.size());
+
+ auto slice = context.timeline->Search(timestamp, pid);
+
+ auto expected_uid = NormalizeUid(slice.uid);
+ auto actual_uid = NormalizeUid(context.package_uid.value());
+
+ return !pid || expected_uid == actual_uid
+ ? pid
+ : context.synthetic_threads->tids[cpu];
+}
+} // namespace
+
+base::Status ThreadMergeRemapFtraceEventPid::Redact(
+ const Context& context,
+ const protos::pbzero::FtraceEventBundle::Decoder& bundle,
+ protozero::ProtoDecoder& event,
+ protos::pbzero::FtraceEvent* event_message) const {
+ if (!context.package_uid.has_value()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapFtraceEventPid: missing package uid");
+ }
+
+ if (!context.synthetic_threads.has_value()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapFtraceEventPid: missing synthetic threads");
+ }
+
+ // This should never happen. A bundle should have a cpu.
+ if (!bundle.has_cpu()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapFtraceEventPid: Invalid ftrace event, missing cpu.");
+ }
+
+ if (bundle.cpu() >= context.synthetic_threads->tids.size()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapFtraceEventPid: synthetic thread count");
+ }
+
+ auto timestamp =
+ event.FindField(protos::pbzero::FtraceEvent::kTimestampFieldNumber);
+
+ // This should never happen. An event should have a timestamp.
+ if (!timestamp.valid()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapFtraceEventPid: Invalid ftrace event, missing "
+ "timestamp.");
+ }
+
+ // This handler should only be called for the pid field.
+ auto pid = event.FindField(protos::pbzero::FtraceEvent::kPidFieldNumber);
+ PERFETTO_DCHECK(pid.valid());
+
+ // The event's pid is technically a uint, but we need it as a int.
+ auto new_pid =
+ RemapPid(context, timestamp.as_uint64(), bundle.cpu(), pid.as_int32());
+ event_message->set_pid(static_cast<uint32_t>(new_pid));
+
+ return base::OkStatus();
+}
+
+base::Status ThreadMergeRemapSchedSwitchPid::Redact(
+ const Context& context,
+ const protos::pbzero::FtraceEventBundle::Decoder& bundle,
+ protozero::ProtoDecoder& event,
+ protos::pbzero::FtraceEvent* event_message) const {
+ if (!context.package_uid.has_value()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedSwitchPid: missing package uid");
+ }
+
+ if (!context.synthetic_threads.has_value()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedSwitchPid: missing synthetic threads");
+ }
+
+ // This should never happen. A bundle should have a cpu.
+ if (!bundle.has_cpu()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedSwitchPid: Invalid ftrace event, missing cpu.");
+ }
+
+ if (bundle.cpu() >= context.synthetic_threads->tids.size()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedSwitchPid: synthetic thread count");
+ }
+
+ auto timestamp =
+ event.FindField(protos::pbzero::FtraceEvent::kTimestampFieldNumber);
+
+ // This should never happen. An event should have a timestamp.
+ if (!timestamp.valid()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedSwitchPid: Invalid ftrace event, missing "
+ "timestamp.");
+ }
+
+ // This handler should only be called for the sched switch field.
+ auto sched_switch =
+ event.FindField(protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber);
+ PERFETTO_DCHECK(sched_switch.valid());
+
+ protozero::ProtoDecoder sched_switch_decoder(sched_switch.as_bytes());
+
+ auto old_prev_pid_field = sched_switch_decoder.FindField(
+ protos::pbzero::SchedSwitchFtraceEvent::kPrevPidFieldNumber);
+ auto old_next_pid_field = sched_switch_decoder.FindField(
+ protos::pbzero::SchedSwitchFtraceEvent::kNextPidFieldNumber);
+
+ if (!old_prev_pid_field.valid()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedSwitchPid: Invalid sched switch event, missing "
+ "prev pid");
+ }
+
+ if (!old_next_pid_field.valid()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedSwitchPid: Invalid sched switch event, missing "
+ "next pid");
+ }
+
+ auto new_prev_pid_field =
+ RemapPid(context, timestamp.as_uint64(), bundle.cpu(),
+ old_prev_pid_field.as_int32());
+ auto new_next_pid_field =
+ RemapPid(context, timestamp.as_uint64(), bundle.cpu(),
+ old_next_pid_field.as_int32());
+
+ auto* sched_switch_message = event_message->set_sched_switch();
+
+ for (auto f = sched_switch_decoder.ReadField(); f.valid();
+ f = sched_switch_decoder.ReadField()) {
+ switch (f.id()) {
+ case protos::pbzero::SchedSwitchFtraceEvent::kPrevPidFieldNumber:
+ sched_switch_message->set_prev_pid(new_prev_pid_field);
+ break;
+
+ case protos::pbzero::SchedSwitchFtraceEvent::kNextPidFieldNumber:
+ sched_switch_message->set_next_pid(new_next_pid_field);
+ break;
+
+ default:
+ proto_util::AppendField(f, sched_switch_message);
+ break;
+ }
+ }
+
+ return base::OkStatus();
+}
+
+base::Status ThreadMergeRemapSchedWakingPid::Redact(
+ const Context& context,
+ const protos::pbzero::FtraceEventBundle::Decoder& bundle,
+ protozero::ProtoDecoder& event,
+ protos::pbzero::FtraceEvent* event_message) const {
+ if (!context.package_uid.has_value()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedWakingPid: missing package uid");
+ }
+
+ if (!context.synthetic_threads.has_value()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedWakingPid: missing synthetic threads");
+ }
+
+ // This should never happen. A bundle should have a cpu.
+ if (!bundle.has_cpu()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedWakingPid: Invalid ftrace event, missing cpu.");
+ }
+
+ if (bundle.cpu() >= context.synthetic_threads->tids.size()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedWakingPid: synthetic thread count");
+ }
+
+ auto timestamp =
+ event.FindField(protos::pbzero::FtraceEvent::kTimestampFieldNumber);
+
+ // This should never happen. An event should have a timestamp.
+ if (!timestamp.valid()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedWakingPid: Invalid ftrace event, missing "
+ "timestamp.");
+ }
+
+ // This handler should only be called for the sched waking field.
+ auto sched_waking =
+ event.FindField(protos::pbzero::FtraceEvent::kSchedWakingFieldNumber);
+ PERFETTO_DCHECK(sched_waking.valid());
+
+ protozero::ProtoDecoder sched_waking_decoder(sched_waking.as_bytes());
+
+ auto old_pid = sched_waking_decoder.FindField(
+ protos::pbzero::SchedWakingFtraceEvent::kPidFieldNumber);
+
+ if (!old_pid.valid()) {
+ return base::ErrStatus(
+ "ThreadMergeRemapSchedWakingPid: Invalid sched waking event, missing "
+ "pid");
+ }
+
+ auto new_pid_field = RemapPid(context, timestamp.as_uint64(), bundle.cpu(),
+ old_pid.as_int32());
+
+ auto* sched_waking_message = event_message->set_sched_waking();
+
+ for (auto f = sched_waking_decoder.ReadField(); f.valid();
+ f = sched_waking_decoder.ReadField()) {
+ if (f.id() == protos::pbzero::SchedWakingFtraceEvent::kPidFieldNumber) {
+ sched_waking_message->set_pid(new_pid_field);
+ } else {
+ proto_util::AppendField(f, sched_waking_message);
+ }
+ }
+
+ return base::OkStatus();
+}
+
+// By doing nothing, the field gets dropped.
+base::Status ThreadMergeDropField::Redact(
+ const Context&,
+ const protos::pbzero::FtraceEventBundle::Decoder&,
+ protozero::ProtoDecoder&,
+ protos::pbzero::FtraceEvent*) const {
+ return base::OkStatus();
+}
+
+} // namespace perfetto::trace_redaction