Add a ProtoLog message decoder class
Used to decode ProtoLog message using the interned ViewerConfig.
Test: tools/ninja -C out/linux_clang_release && tools/diff_test_trace_processor.py ./out/linux_clang_release/trace_processor_shell --name-filter "ProtoLog"
Change-Id: I3ba178e46f8686fbe1f851e2941363f377c68bef
diff --git a/Android.bp b/Android.bp
index 7c6d340..63bebff 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12526,6 +12526,7 @@
name: "perfetto_src_trace_processor_importers_proto_winscope_full",
srcs: [
"src/trace_processor/importers/proto/winscope/android_input_event_parser.cc",
+ "src/trace_processor/importers/proto/winscope/protolog_message_decoder.cc",
"src/trace_processor/importers/proto/winscope/protolog_messages_tracker.cc",
"src/trace_processor/importers/proto/winscope/protolog_parser.cc",
"src/trace_processor/importers/proto/winscope/shell_transitions_parser.cc",
diff --git a/BUILD b/BUILD
index 52bb806..51b3356 100644
--- a/BUILD
+++ b/BUILD
@@ -1768,6 +1768,8 @@
srcs = [
"src/trace_processor/importers/proto/winscope/android_input_event_parser.cc",
"src/trace_processor/importers/proto/winscope/android_input_event_parser.h",
+ "src/trace_processor/importers/proto/winscope/protolog_message_decoder.cc",
+ "src/trace_processor/importers/proto/winscope/protolog_message_decoder.h",
"src/trace_processor/importers/proto/winscope/protolog_messages_tracker.cc",
"src/trace_processor/importers/proto/winscope/protolog_messages_tracker.h",
"src/trace_processor/importers/proto/winscope/protolog_parser.cc",
diff --git a/src/trace_processor/importers/proto/winscope/BUILD.gn b/src/trace_processor/importers/proto/winscope/BUILD.gn
index 682fc4b..ab09809 100644
--- a/src/trace_processor/importers/proto/winscope/BUILD.gn
+++ b/src/trace_processor/importers/proto/winscope/BUILD.gn
@@ -18,6 +18,8 @@
sources = [
"android_input_event_parser.cc",
"android_input_event_parser.h",
+ "protolog_message_decoder.cc",
+ "protolog_message_decoder.h",
"protolog_messages_tracker.cc",
"protolog_messages_tracker.h",
"protolog_parser.cc",
diff --git a/src/trace_processor/importers/proto/winscope/protolog_message_decoder.cc b/src/trace_processor/importers/proto/winscope/protolog_message_decoder.cc
new file mode 100644
index 0000000..739c540
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/protolog_message_decoder.cc
@@ -0,0 +1,136 @@
+/*
+ * 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_processor/importers/proto/winscope/protolog_message_decoder.h"
+
+#include <cstdint>
+#include <optional>
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/string_view.h"
+
+namespace perfetto::trace_processor {
+
+ProtoLogMessageDecoder::ProtoLogMessageDecoder() = default;
+ProtoLogMessageDecoder::~ProtoLogMessageDecoder() = default;
+
+std::optional<DecodedMessage> ProtoLogMessageDecoder::Decode(
+ uint64_t message_id,
+ const std::vector<int64_t>& sint64_params,
+ const std::vector<double>& double_params,
+ const std::vector<bool>& boolean_params,
+ const std::vector<std::string>& string_params) {
+ auto tracked_message = tracked_messages_.Find(message_id);
+ if (tracked_message == nullptr) {
+ return std::nullopt;
+ }
+
+ auto message = tracked_message->message;
+
+ auto group = tracked_groups_.Find(tracked_message->group_id);
+ if (group == nullptr) {
+ return std::nullopt;
+ }
+
+ std::string formatted_message;
+ formatted_message.reserve(message.size());
+
+ auto sint64_params_itr = sint64_params.begin();
+ auto double_params_itr = double_params.begin();
+ auto boolean_params_itr = boolean_params.begin();
+ auto str_params_itr = string_params.begin();
+
+ for (size_t i = 0; i < message.length();) {
+ if (message.at(i) == '%' && i + 1 < message.length()) {
+ switch (message.at(i + 1)) {
+ case '%':
+ break;
+ case 'd': {
+ base::StackString<32> param("%" PRId64, *sint64_params_itr);
+ formatted_message.append(param.c_str());
+ ++sint64_params_itr;
+ break;
+ }
+ case 'o': {
+ base::StackString<32> param("%" PRIo64, *sint64_params_itr);
+ formatted_message.append(param.c_str());
+ ++sint64_params_itr;
+ break;
+ }
+ case 'x': {
+ base::StackString<32> param("%" PRIx64, *sint64_params_itr);
+ formatted_message.append(param.c_str());
+ ++sint64_params_itr;
+ break;
+ }
+ case 'f': {
+ base::StackString<32> param("%f", *double_params_itr);
+ formatted_message.append(param.c_str());
+ ++double_params_itr;
+ break;
+ }
+ case 'e': {
+ base::StackString<32> param("%e", *double_params_itr);
+ formatted_message.append(param.c_str());
+ ++double_params_itr;
+ break;
+ }
+ case 'g': {
+ base::StackString<32> param("%g", *double_params_itr);
+ formatted_message.append(param.c_str());
+ ++double_params_itr;
+ break;
+ }
+ case 's': {
+ formatted_message.append(*str_params_itr);
+ ++str_params_itr;
+ break;
+ }
+ case 'b': {
+ formatted_message.append(*boolean_params_itr ? "true" : "false");
+ ++boolean_params_itr;
+ break;
+ }
+ default:
+ formatted_message.push_back(message[i]);
+ formatted_message.push_back(message[i + 1]);
+ }
+
+ i += 2;
+ } else {
+ formatted_message.push_back(message[i]);
+ i += 1;
+ }
+ }
+
+ return DecodedMessage{tracked_message->level, group->tag, formatted_message};
+}
+
+void ProtoLogMessageDecoder::TrackGroup(uint32_t id, const std::string& tag) {
+ tracked_groups_.Insert(id, TrackedGroup{tag});
+}
+
+void ProtoLogMessageDecoder::TrackMessage(uint64_t message_id,
+ ProtoLogLevel level,
+ uint32_t group_id,
+ const std::string& message) {
+ tracked_messages_.Insert(message_id,
+ TrackedMessage{level, group_id, message});
+}
+
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/proto/winscope/protolog_message_decoder.h b/src/trace_processor/importers/proto/winscope/protolog_message_decoder.h
new file mode 100644
index 0000000..55388b4
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/protolog_message_decoder.h
@@ -0,0 +1,92 @@
+/*
+ * 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_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_PROTOLOG_MESSAGE_DECODER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_PROTOLOG_MESSAGE_DECODER_H_
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/tables/winscope_tables_py.h"
+#include "src/trace_processor/types/destructible.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto::trace_processor {
+
+enum ProtoLogLevel : int32_t {
+ DEBUG = 1,
+ VERBOSE = 2,
+ INFO = 3,
+ WARN = 4,
+ ERROR = 5,
+ WTF = 6,
+};
+
+struct DecodedMessage {
+ ProtoLogLevel log_level;
+ std::string group_tag;
+ std::string message;
+};
+
+struct TrackedGroup {
+ std::string tag;
+};
+
+struct TrackedMessage {
+ ProtoLogLevel level;
+ uint32_t group_id;
+ std::string message;
+};
+
+class ProtoLogMessageDecoder : public Destructible {
+ public:
+ explicit ProtoLogMessageDecoder();
+ virtual ~ProtoLogMessageDecoder() override;
+
+ static ProtoLogMessageDecoder* GetOrCreate(TraceProcessorContext* context) {
+ if (!context->protolog_message_decoder) {
+ context->protolog_message_decoder.reset(new ProtoLogMessageDecoder());
+ }
+ return static_cast<ProtoLogMessageDecoder*>(
+ context->protolog_message_decoder.get());
+ }
+
+ std::optional<DecodedMessage> Decode(
+ uint64_t message_id,
+ const std::vector<int64_t>& sint64_params,
+ const std::vector<double>& double_params,
+ const std::vector<bool>& boolean_params,
+ const std::vector<std::string>& string_params);
+
+ void TrackGroup(uint32_t id, const std::string& tag);
+
+ void TrackMessage(uint64_t message_id,
+ ProtoLogLevel level,
+ uint32_t group_id,
+ const std::string& message);
+
+ private:
+ base::FlatHashMap<uint64_t, TrackedGroup> tracked_groups_;
+ base::FlatHashMap<uint64_t, TrackedMessage> tracked_messages_;
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_PROTOLOG_MESSAGE_DECODER_H_
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index 3ec964f..63c3ee7 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -146,6 +146,7 @@
std::unique_ptr<Destructible> v8_tracker; // V8Tracker
std::unique_ptr<Destructible> jit_tracker; // JitTracker
std::unique_ptr<Destructible> perf_dso_tracker; // DsoTracker
+ std::unique_ptr<Destructible> protolog_message_decoder; // ProtoLogMessageDecoder
// clang-format on
std::unique_ptr<ProtoTraceParser> proto_trace_parser;