Merge "tp: binder_tracker: fix performance issue due to insert/erase heavy workload + FlatHashMap" into main
diff --git a/Android.bp b/Android.bp
index 73b4ae5..438f7d6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13463,6 +13463,7 @@
"src/trace_redaction/filter_sched_waking_events.cc",
"src/trace_redaction/filter_task_rename.cc",
"src/trace_redaction/find_package_uid.cc",
+ "src/trace_redaction/modify_process_trees.cc",
"src/trace_redaction/optimize_timeline.cc",
"src/trace_redaction/populate_allow_lists.cc",
"src/trace_redaction/process_thread_timeline.cc",
diff --git a/src/trace_redaction/BUILD.gn b/src/trace_redaction/BUILD.gn
index 037545d..8ff31a3 100644
--- a/src/trace_redaction/BUILD.gn
+++ b/src/trace_redaction/BUILD.gn
@@ -47,6 +47,8 @@
"find_package_uid.cc",
"find_package_uid.h",
"frame_cookie.h",
+ "modify_process_trees.cc",
+ "modify_process_trees.h",
"optimize_timeline.cc",
"optimize_timeline.h",
"populate_allow_lists.cc",
diff --git a/src/trace_redaction/modify_process_trees.cc b/src/trace_redaction/modify_process_trees.cc
new file mode 100644
index 0000000..099890b
--- /dev/null
+++ b/src/trace_redaction/modify_process_trees.cc
@@ -0,0 +1,114 @@
+/*
+ * 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/modify_process_trees.h"
+
+#include <string>
+
+#include "perfetto/base/status.h"
+#include "perfetto/protozero/field.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "src/trace_redaction/proto_util.h"
+#include "src/trace_redaction/trace_redaction_framework.h"
+
+#include "protos/perfetto/trace/ps/process_tree.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto::trace_redaction {
+
+base::Status ModifyProcessTree::VerifyContext(const Context&) const {
+ return base::OkStatus();
+}
+
+base::Status ModifyProcessTree::Transform(const Context& context,
+ std::string* packet) const {
+ protozero::ProtoDecoder decoder(*packet);
+
+ auto process_tree =
+ decoder.FindField(protos::pbzero::TracePacket::kProcessTreeFieldNumber);
+
+ if (!process_tree.valid()) {
+ return base::OkStatus();
+ }
+
+ auto timestamp =
+ decoder.FindField(protos::pbzero::TracePacket::kTimestampFieldNumber);
+
+ protozero::HeapBuffered<protos::pbzero::TracePacket> packet_message;
+
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ if (field.id() == protos::pbzero::TracePacket::kProcessTreeFieldNumber) {
+ TransformProcessTree(context, timestamp, field,
+ packet_message->set_process_tree());
+ } else {
+ proto_util::AppendField(field, packet_message.get());
+ }
+ }
+
+ packet->assign(packet_message.SerializeAsString());
+
+ return base::OkStatus();
+}
+
+void ModifyProcessTree::TransformProcess(
+ const Context&,
+ const protozero::Field&,
+ const protozero::Field& process,
+ protos::pbzero::ProcessTree* process_tree) const {
+ PERFETTO_DCHECK(process.id() ==
+ protos::pbzero::ProcessTree::kProcessesFieldNumber);
+ proto_util::AppendField(process, process_tree);
+}
+
+void ModifyProcessTree::TransformThread(
+ const Context&,
+ const protozero::Field&,
+ const protozero::Field& thread,
+ protos::pbzero::ProcessTree* process_tree) const {
+ PERFETTO_DCHECK(thread.id() ==
+ protos::pbzero::ProcessTree::kThreadsFieldNumber);
+ proto_util::AppendField(thread, process_tree);
+}
+
+void ModifyProcessTree::TransformProcessTree(
+ const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& process_tree,
+ protos::pbzero::ProcessTree* message) const {
+ protozero::ProtoDecoder decoder(process_tree.as_bytes());
+
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ switch (field.id()) {
+ case protos::pbzero::ProcessTree::kProcessesFieldNumber:
+ TransformProcess(context, timestamp, field, message);
+ break;
+
+ case protos::pbzero::ProcessTree::kThreadsFieldNumber:
+ TransformThread(context, timestamp, field, message);
+ break;
+
+ default:
+ proto_util::AppendField(field, message);
+ break;
+ }
+ }
+
+ // TODO(vaage): Call the handler to add extra fields to the process tree.
+}
+
+} // namespace perfetto::trace_redaction
diff --git a/src/trace_redaction/modify_process_trees.h b/src/trace_redaction/modify_process_trees.h
new file mode 100644
index 0000000..e36223e
--- /dev/null
+++ b/src/trace_redaction/modify_process_trees.h
@@ -0,0 +1,70 @@
+/*
+ * 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_MODIFY_PROCESS_TREES_H_
+#define SRC_TRACE_REDACTION_MODIFY_PROCESS_TREES_H_
+
+#include <string>
+
+#include "perfetto/base/status.h"
+#include "src/trace_redaction/trace_redaction_framework.h"
+
+#include "protos/perfetto/trace/ps/process_tree.pbzero.h"
+
+namespace perfetto::trace_redaction {
+
+// Walk through process trees, calling process and thread handlers to add new
+// process and threads messages to the process tree. If the default handler is
+// not replaced, the thread/process will be added to the parent.
+class ModifyProcessTree : public TransformPrimitive {
+ public:
+ base::Status Transform(const Context& context,
+ std::string* packet) const override;
+
+ protected:
+ // Verifies that the context contains required values. No-op by default.
+ virtual base::Status VerifyContext(const Context& context) const;
+
+ // Modifies a process before adding it back to the process tree. Appends the
+ // field to the process tree without modification by default.
+ virtual void TransformProcess(
+ const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& process,
+ protos::pbzero::ProcessTree* process_tree) const;
+
+ // Modifies a thread before adding it back to the process tree. Appends the
+ // field to the process tree without modification by default.
+ virtual void TransformThread(
+ const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& thread,
+ protos::pbzero::ProcessTree* process_trees) const;
+
+ // TODO(vaage): Add a handler that is called the process tree is populated so
+ // that fields can be added to process tree (e.g. creating new threads -
+ // needed for thread merging).
+
+ private:
+ void TransformProcessTree(const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& process_tree,
+ protos::pbzero::ProcessTree* message) const;
+};
+
+} // namespace perfetto::trace_redaction
+
+#endif // SRC_TRACE_REDACTION_MODIFY_PROCESS_TREES_H_
diff --git a/src/trace_redaction/populate_allow_lists.cc b/src/trace_redaction/populate_allow_lists.cc
index b2c9431..11d895b 100644
--- a/src/trace_redaction/populate_allow_lists.cc
+++ b/src/trace_redaction/populate_allow_lists.cc
@@ -84,24 +84,38 @@
context->trace_packet_allow_list.insert(item);
}
+ // FTRACE EVENT NOTES
+ //
+ // Dma events (kDmaHeapStatFieldNumber) are global events and are not
+ // emitted within a process context (they are centrally allocated by the
+ // HAL process). We drop them for now as we don't have the required
+ // attribution info in the trace.
+ //
+ // ION events (e.g. kIonBufferCreateFieldNumber, kIonHeapGrowFieldNumber,
+ // etc.) are global events are not emitted within a process context (they
+ // are centrally allocated by the HAL process). We drop them for now as we
+ // don't have the required attribution info in the trace.
+ //
+ // TODO(vaage): The allowed rss stat events (i.e. kRssStatFieldNumber,
+ // kRssStatThrottledFieldNumber) are process-scoped. It is non-trivial to
+ // merge events, so all events outside of the target package should be
+ // dropped.
+ //
+ // TODO(vaage): kSchedBlockedReasonFieldNumber contains two pids, an outer
+ // and inner pid. A primitive is needed to further redact these events.
+
std::initializer_list<uint32_t> ftrace_events = {
- protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber,
protos::pbzero::FtraceEvent::kCpuFrequencyFieldNumber,
protos::pbzero::FtraceEvent::kCpuIdleFieldNumber,
+ protos::pbzero::FtraceEvent::kPrintFieldNumber,
+ protos::pbzero::FtraceEvent::kRssStatFieldNumber,
+ protos::pbzero::FtraceEvent::kRssStatThrottledFieldNumber,
protos::pbzero::FtraceEvent::kSchedBlockedReasonFieldNumber,
+ protos::pbzero::FtraceEvent::kSchedProcessFreeFieldNumber,
+ protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber,
protos::pbzero::FtraceEvent::kSchedWakingFieldNumber,
protos::pbzero::FtraceEvent::kTaskNewtaskFieldNumber,
protos::pbzero::FtraceEvent::kTaskRenameFieldNumber,
- protos::pbzero::FtraceEvent::kSchedProcessFreeFieldNumber,
- protos::pbzero::FtraceEvent::kRssStatFieldNumber,
- protos::pbzero::FtraceEvent::kIonHeapShrinkFieldNumber,
- protos::pbzero::FtraceEvent::kIonHeapGrowFieldNumber,
- protos::pbzero::FtraceEvent::kIonStatFieldNumber,
- protos::pbzero::FtraceEvent::kIonBufferCreateFieldNumber,
- protos::pbzero::FtraceEvent::kIonBufferDestroyFieldNumber,
- protos::pbzero::FtraceEvent::kDmaHeapStatFieldNumber,
- protos::pbzero::FtraceEvent::kRssStatThrottledFieldNumber,
- protos::pbzero::FtraceEvent::kPrintFieldNumber,
};
for (auto item : ftrace_events) {
diff --git a/src/trace_redaction/scrub_process_trees.cc b/src/trace_redaction/scrub_process_trees.cc
index d8baf99..989d094 100644
--- a/src/trace_redaction/scrub_process_trees.cc
+++ b/src/trace_redaction/scrub_process_trees.cc
@@ -16,9 +16,6 @@
#include "src/trace_redaction/scrub_process_trees.h"
-#include <cstdint>
-#include <string>
-
#include "perfetto/base/status.h"
#include "perfetto/protozero/field.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
@@ -29,149 +26,90 @@
#include "protos/perfetto/trace/trace_packet.pbzero.h"
namespace perfetto::trace_redaction {
+
namespace {
-constexpr auto kThreadsFieldNumber =
- protos::pbzero::ProcessTree::kThreadsFieldNumber;
-constexpr auto kTimestampFieldNumber =
- protos::pbzero::TracePacket::kTimestampFieldNumber;
-constexpr auto kProcessTreeFieldNumber =
- protos::pbzero::TracePacket::kProcessTreeFieldNumber;
-constexpr auto kProcessesFieldNumber =
- protos::pbzero::ProcessTree::kProcessesFieldNumber;
-
-// Skips the cmdline fields.
-void ClearProcessName(protozero::ConstBytes bytes,
- protos::pbzero::ProcessTree::Process* message) {
- protozero::ProtoDecoder decoder(bytes);
-
- for (auto field = decoder.ReadField(); field; field = decoder.ReadField()) {
- if (field.id() !=
- protos::pbzero::ProcessTree::Process::kCmdlineFieldNumber) {
- proto_util::AppendField(field, message);
- }
- }
-}
-
-void ScrubProcess(protozero::Field field,
- const ProcessThreadTimeline& timeline,
- uint64_t now,
- uint64_t uid,
- protos::pbzero::ProcessTree* message) {
- if (field.id() != kProcessesFieldNumber) {
- PERFETTO_FATAL(
- "ScrubProcess() should only be called with a ProcessTree::Processes");
+// Appends a value to the message if (and only if) the pid belongs to the target
+// package.
+void TryAppendPid(const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& pid,
+ const protozero::Field& value,
+ protozero::Message* message) {
+ // All valid processes with have a time and pid/tid values. However, if
+ // they're missing values, the trace is corrupt. To avoid making this work by
+ // dropping too much data, drop the cmdline for all processes.
+ if (!timestamp.valid() || !pid.valid()) {
+ return;
}
- protos::pbzero::ProcessTree::Process::Decoder decoder(field.as_bytes());
- auto slice = timeline.Search(now, decoder.pid());
+ auto slice = context.timeline->Search(timestamp.as_uint64(), pid.as_int32());
- if (NormalizeUid(slice.uid) == NormalizeUid(uid)) {
- proto_util::AppendField(field, message);
- } else {
- ClearProcessName(field.as_bytes(), message->add_processes());
- }
-}
-
-// The thread name is unused, but it's safer to remove it.
-void ClearThreadName(protozero::ConstBytes bytes,
- protos::pbzero::ProcessTree::Thread* message) {
- protozero::ProtoDecoder decoder(bytes);
-
- for (auto field = decoder.ReadField(); field; field = decoder.ReadField()) {
- if (field.id() != protos::pbzero::ProcessTree::Thread::kNameFieldNumber) {
- proto_util::AppendField(field, message);
- }
- }
-}
-
-void ScrubThread(protozero::Field field,
- const ProcessThreadTimeline& timeline,
- uint64_t now,
- uint64_t uid,
- protos::pbzero::ProcessTree* message) {
- if (field.id() != kThreadsFieldNumber) {
- PERFETTO_FATAL(
- "ScrubThread() should only be called with a ProcessTree::Threads");
+ // Only keep the target process cmdline.
+ if (NormalizeUid(slice.uid) != NormalizeUid(context.package_uid.value())) {
+ return;
}
- protos::pbzero::ProcessTree::Thread::Decoder thread_decoder(field.as_bytes());
- auto slice = timeline.Search(now, thread_decoder.tid());
-
- if (NormalizeUid(slice.uid) == NormalizeUid(uid)) {
- proto_util::AppendField(field, message);
- } else {
- ClearThreadName(field.as_bytes(), message->add_threads());
- }
+ proto_util::AppendField(value, message);
}
} // namespace
-base::Status ScrubProcessTrees::Transform(const Context& context,
- std::string* packet) const {
+base::Status ScrubProcessTrees::VerifyContext(const Context& context) const {
if (!context.package_uid.has_value()) {
return base::ErrStatus("ScrubProcessTrees: missing package uid.");
}
- if (context.timeline == nullptr) {
+ if (!context.timeline) {
return base::ErrStatus("ScrubProcessTrees: missing timeline.");
}
- protozero::ProtoDecoder decoder(*packet);
-
- if (!decoder.FindField(kProcessTreeFieldNumber).valid()) {
- return base::OkStatus();
- }
-
- auto timestamp_field = decoder.FindField(kTimestampFieldNumber);
-
- if (!timestamp_field.valid()) {
- return base::ErrStatus("ScrubProcessTrees: trace packet missing timestamp");
- }
-
- auto timestamp = timestamp_field.as_uint64();
-
- auto uid = context.package_uid.value();
-
- const auto& timeline = *context.timeline.get();
-
- protozero::HeapBuffered<protos::pbzero::TracePacket> message;
-
- for (auto packet_field = decoder.ReadField(); packet_field.valid();
- packet_field = decoder.ReadField()) {
- if (packet_field.id() != kProcessTreeFieldNumber) {
- proto_util::AppendField(packet_field, message.get());
- continue;
- }
-
- auto* process_tree_message = message->set_process_tree();
-
- protozero::ProtoDecoder process_tree_decoder(packet_field.as_bytes());
-
- for (auto process_tree_field = process_tree_decoder.ReadField();
- process_tree_field.valid();
- process_tree_field = process_tree_decoder.ReadField()) {
- switch (process_tree_field.id()) {
- case kProcessesFieldNumber:
- ScrubProcess(process_tree_field, timeline, timestamp, uid,
- process_tree_message);
- break;
-
- case kThreadsFieldNumber:
- ScrubThread(process_tree_field, timeline, timestamp, uid,
- process_tree_message);
- break;
-
- default:
- proto_util::AppendField(process_tree_field, process_tree_message);
- break;
- }
- }
- }
-
- packet->assign(message.SerializeAsString());
-
return base::OkStatus();
}
+void ScrubProcessTrees::TransformProcess(
+ const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& process,
+ protos::pbzero::ProcessTree* process_tree) const {
+ protozero::ProtoDecoder decoder(process.as_bytes());
+
+ auto pid =
+ decoder.FindField(protos::pbzero::ProcessTree::Process::kPidFieldNumber);
+
+ auto* process_message = process_tree->add_processes();
+
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ if (field.id() ==
+ protos::pbzero::ProcessTree::Process::kCmdlineFieldNumber) {
+ TryAppendPid(context, timestamp, pid, field, process_message);
+ } else {
+ proto_util::AppendField(field, process_message);
+ }
+ }
+}
+
+void ScrubProcessTrees::TransformThread(
+ const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& thread,
+ protos::pbzero::ProcessTree* process_tree) const {
+ protozero::ProtoDecoder decoder(thread.as_bytes());
+
+ auto tid =
+ decoder.FindField(protos::pbzero::ProcessTree::Thread::kTidFieldNumber);
+
+ auto* thread_message = process_tree->add_threads();
+
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ if (field.id() == protos::pbzero::ProcessTree::Thread::kNameFieldNumber) {
+ TryAppendPid(context, timestamp, tid, field, thread_message);
+ } else {
+ proto_util::AppendField(field, thread_message);
+ }
+ }
+}
+
} // namespace perfetto::trace_redaction
diff --git a/src/trace_redaction/scrub_process_trees.h b/src/trace_redaction/scrub_process_trees.h
index 61cb85a..7c2b07a 100644
--- a/src/trace_redaction/scrub_process_trees.h
+++ b/src/trace_redaction/scrub_process_trees.h
@@ -17,19 +17,32 @@
#ifndef SRC_TRACE_REDACTION_SCRUB_PROCESS_TREES_H_
#define SRC_TRACE_REDACTION_SCRUB_PROCESS_TREES_H_
-#include <string>
-
#include "perfetto/base/status.h"
+#include "perfetto/protozero/field.h"
+#include "src/trace_redaction/modify_process_trees.h"
#include "src/trace_redaction/trace_redaction_framework.h"
+#include "protos/perfetto/trace/ps/process_tree.pbzero.h"
+
namespace perfetto::trace_redaction {
// Removes process names and thread names from process_trees if their pids/tids
// are not connected to the target package.
-class ScrubProcessTrees final : public TransformPrimitive {
- public:
- base::Status Transform(const Context& context,
- std::string* packet) const override;
+class ScrubProcessTrees : public ModifyProcessTree {
+ protected:
+ base::Status VerifyContext(const Context& context) const override;
+
+ void TransformProcess(
+ const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& process,
+ protos::pbzero::ProcessTree* process_trees) const override;
+
+ void TransformThread(
+ const Context& context,
+ const protozero::Field& timestamp,
+ const protozero::Field& thread,
+ protos::pbzero::ProcessTree* process_tree) const override;
};
} // namespace perfetto::trace_redaction