Allow to produce DeobfuscationMapping from proguard map.

Bug: 143611277
Change-Id: Ia3f65830b7483b48baed4e835b0fee39f5538ce7
diff --git a/Android.bp b/Android.bp
index b7a3a33..85f661e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5192,6 +5192,7 @@
 filegroup {
   name: "perfetto_tools_trace_to_text_common",
   srcs: [
+    "tools/trace_to_text/deobfuscate_profile.cc",
     "tools/trace_to_text/main.cc",
     "tools/trace_to_text/symbolize_profile.cc",
     "tools/trace_to_text/trace_to_json.cc",
@@ -5729,6 +5730,7 @@
     ":perfetto_include_perfetto_base_base",
     ":perfetto_include_perfetto_ext_base_base",
     ":perfetto_include_perfetto_ext_traced_sys_stats_counters",
+    ":perfetto_include_perfetto_profiling_deobfuscator",
     ":perfetto_include_perfetto_profiling_symbolizer",
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_trace_processor_basic_types",
@@ -5787,6 +5789,7 @@
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_protos_third_party_pprof_lite_gen",
     ":perfetto_src_base_base",
+    ":perfetto_src_profiling_deobfuscator",
     ":perfetto_src_protozero_protozero",
     ":perfetto_src_trace_processor_common",
     ":perfetto_src_trace_processor_db_lib",
diff --git a/BUILD b/BUILD
index 57831e6..c7db1e7 100644
--- a/BUILD
+++ b/BUILD
@@ -330,6 +330,14 @@
     ],
 )
 
+# GN target: //include/perfetto/profiling:deobfuscator
+filegroup(
+    name = "include_perfetto_profiling_deobfuscator",
+    srcs = [
+        "include/perfetto/profiling/deobfuscator.h",
+    ],
+)
+
 # GN target: //include/perfetto/profiling:symbolizer
 filegroup(
     name = "include_perfetto_profiling_symbolizer",
@@ -524,6 +532,14 @@
     ],
 )
 
+# GN target: //src/profiling:deobfuscator
+filegroup(
+    name = "src_profiling_deobfuscator",
+    srcs = [
+        "src/profiling/deobfuscator.cc",
+    ],
+)
+
 # GN target: //src/protozero:protozero
 filegroup(
     name = "src_protozero_protozero",
@@ -1090,6 +1106,8 @@
 filegroup(
     name = "tools_trace_to_text_common",
     srcs = [
+        "tools/trace_to_text/deobfuscate_profile.cc",
+        "tools/trace_to_text/deobfuscate_profile.h",
         "tools/trace_to_text/main.cc",
         "tools/trace_to_text/symbolize_profile.cc",
         "tools/trace_to_text/symbolize_profile.h",
@@ -2552,6 +2570,7 @@
     name = "libpprofbuilder",
     srcs = [
         ":src_base_base",
+        ":src_profiling_deobfuscator",
         ":src_protozero_protozero",
         ":src_trace_processor_common",
         ":src_trace_processor_db_lib",
@@ -2570,6 +2589,7 @@
         ":include_perfetto_ext_base_base",
         ":include_perfetto_ext_trace_processor_export_json",
         ":include_perfetto_ext_traced_sys_stats_counters",
+        ":include_perfetto_profiling_deobfuscator",
         ":include_perfetto_profiling_symbolizer",
         ":include_perfetto_protozero_protozero",
         ":include_perfetto_trace_processor_basic_types",
@@ -2648,12 +2668,14 @@
         ":include_perfetto_ext_base_base",
         ":include_perfetto_ext_trace_processor_export_json",
         ":include_perfetto_ext_traced_sys_stats_counters",
+        ":include_perfetto_profiling_deobfuscator",
         ":include_perfetto_profiling_symbolizer",
         ":include_perfetto_protozero_protozero",
         ":include_perfetto_trace_processor_basic_types",
         ":include_perfetto_trace_processor_storage",
         ":include_perfetto_trace_processor_trace_processor",
         ":src_base_base",
+        ":src_profiling_deobfuscator",
         ":src_protozero_protozero",
         ":src_trace_processor_common",
         ":src_trace_processor_db_lib",
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index abfe920..7faa5d4 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -3045,7 +3045,7 @@
 message DeobfuscationMapping {
   optional string package_name = 1;
   optional int64 version_code = 2;
-  repeated ObfuscatedClass obfusucated_classes = 3;
+  repeated ObfuscatedClass obfuscated_classes = 3;
 }
 
 message HeapGraphRoot {
@@ -3554,7 +3554,7 @@
 // TracePacket(s).
 //
 // Next reserved id: 13 (up to 15).
-// Next id: 64.
+// Next id: 65.
 message TracePacket {
   // The timestamp of the TracePacket.
   // By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -3608,6 +3608,7 @@
     // Only used in profile packets.
     ProfiledFrameSymbols profiled_frame_symbols = 55;
     ModuleSymbols module_symbols = 61;
+    DeobfuscationMapping deobfuscation_mapping = 64;
 
     // Only used by TrackEvent.
     TrackDescriptor track_descriptor = 60;
diff --git a/protos/perfetto/trace/profiling/heap_graph.proto b/protos/perfetto/trace/profiling/heap_graph.proto
index 5601b9b..933d2d0 100644
--- a/protos/perfetto/trace/profiling/heap_graph.proto
+++ b/protos/perfetto/trace/profiling/heap_graph.proto
@@ -38,7 +38,7 @@
 message DeobfuscationMapping {
   optional string package_name = 1;
   optional int64 version_code = 2;
-  repeated ObfuscatedClass obfusucated_classes = 3;
+  repeated ObfuscatedClass obfuscated_classes = 3;
 }
 
 message HeapGraphRoot {
diff --git a/protos/perfetto/trace/trace_packet.proto b/protos/perfetto/trace/trace_packet.proto
index b23c98b..95e9eef 100644
--- a/protos/perfetto/trace/trace_packet.proto
+++ b/protos/perfetto/trace/trace_packet.proto
@@ -58,7 +58,7 @@
 // TracePacket(s).
 //
 // Next reserved id: 13 (up to 15).
-// Next id: 64.
+// Next id: 65.
 message TracePacket {
   // The timestamp of the TracePacket.
   // By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -112,6 +112,7 @@
     // Only used in profile packets.
     ProfiledFrameSymbols profiled_frame_symbols = 55;
     ModuleSymbols module_symbols = 61;
+    DeobfuscationMapping deobfuscation_mapping = 64;
 
     // Only used by TrackEvent.
     TrackDescriptor track_descriptor = 60;
diff --git a/src/profiling/deobfuscator.cc b/src/profiling/deobfuscator.cc
index 8306ded..a8b7652 100644
--- a/src/profiling/deobfuscator.cc
+++ b/src/profiling/deobfuscator.cc
@@ -117,21 +117,31 @@
     std::tie(obfuscated_name, deobfuscated_name) = *opt_pair;
     auto p = mapping_.emplace(std::move(obfuscated_name),
                               std::move(deobfuscated_name));
-    if (!p.second)
+    if (!p.second) {
+      PERFETTO_ELOG("Duplicate class.");
       return false;
+    }
     current_class_ = &p.first->second;
   } else {
-    // TODO(fmayer): Teach this to properly parse methods.
     std::string obfuscated_name;
     std::string deobfuscated_name;
     auto opt_pair = ParseMember(std::move(line));
     if (!opt_pair)
       return false;
     std::tie(obfuscated_name, deobfuscated_name) = *opt_pair;
-    auto p = current_class_->deobfuscated_fields.emplace(
-        std::move(obfuscated_name), std::move(deobfuscated_name));
-    if (!p.second)
+    // TODO(fmayer): Teach this to properly parse methods.
+    if (deobfuscated_name.find("(") != std::string::npos) {
+      // Skip functions, as they will trigger the "Duplicate member" below.
+      return true;
+    }
+    auto p = current_class_->deobfuscated_fields.emplace(obfuscated_name,
+                                                         deobfuscated_name);
+    if (!p.second && p.first->second != deobfuscated_name) {
+      PERFETTO_ELOG("Member redefinition: %s.%s",
+                    current_class_->deobfuscated_name.c_str(),
+                    deobfuscated_name.c_str());
       return false;
+    }
   }
   return true;
 }
diff --git a/src/profiling/deobfuscator_unittest.cc b/src/profiling/deobfuscator_unittest.cc
index 0b7833e..0d9619a 100644
--- a/src/profiling/deobfuscator_unittest.cc
+++ b/src/profiling/deobfuscator_unittest.cc
@@ -79,7 +79,7 @@
   ASSERT_TRUE(p.AddLine(
       "android.arch.core.executor.ArchTaskExecutor -> android.arch.a.a.a:"));
   ASSERT_FALSE(p.AddLine(
-      "android.arch.core.executor.ArchTaskExecutor -> android.arch.a.a.a:"));
+      "android.arch.core.executor.ArchTaskExecutor2 -> android.arch.a.a.a:"));
 }
 
 TEST(ProguardParserTest, DuplicateField) {
@@ -89,7 +89,7 @@
   ASSERT_TRUE(
       p.AddLine("    android.arch.core.executor.TaskExecutor mDelegate -> b"));
   ASSERT_FALSE(
-      p.AddLine("    android.arch.core.executor.TaskExecutor mDelegate -> b"));
+      p.AddLine("    android.arch.core.executor.TaskExecutor mDelegate2 -> b"));
 }
 
 }  // namespace
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index 5ddea68..d7ae08f 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -39,6 +39,8 @@
 source_set("utils") {
   deps = [
     ":symbolizer",
+    "../../include/perfetto/profiling:deobfuscator",
+    "../../src/profiling:deobfuscator",
   ]
   public_deps = [
     "../../gn:default_deps",
@@ -128,6 +130,8 @@
     ":pprofbuilder",
     ":symbolizer",
     ":utils",
+    "../../include/perfetto/profiling:deobfuscator",
+    "../../src/profiling:deobfuscator",
   ]
   public_deps = [
     "../../gn:default_deps",
@@ -143,6 +147,8 @@
     "../../src/trace_processor:lib",
   ]
   sources = [
+    "deobfuscate_profile.cc",
+    "deobfuscate_profile.h",
     "main.cc",
     "symbolize_profile.cc",
     "symbolize_profile.h",
diff --git a/tools/trace_to_text/deobfuscate_profile.cc b/tools/trace_to_text/deobfuscate_profile.cc
new file mode 100644
index 0000000..1d1af52
--- /dev/null
+++ b/tools/trace_to_text/deobfuscate_profile.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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 <stdio.h>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/profiling/deobfuscator.h"
+#include "protos/perfetto/trace/trace_packet.pb.h"
+#include "tools/trace_to_text/deobfuscate_profile.h"
+#include "tools/trace_to_text/utils.h"
+
+namespace perfetto {
+namespace trace_to_text {
+namespace {
+
+bool ParseFile(profiling::ProguardParser* p, FILE* f) {
+  std::vector<std::string> lines;
+  size_t n = 0;
+  char* line = nullptr;
+  ssize_t rd = 0;
+  bool success = true;
+  do {
+    rd = getline(&line, &n, f);
+    // Do not read empty line that terminates the output.
+    if (rd > 1) {
+      // Remove newline character.
+      PERFETTO_DCHECK(line[rd - 1] == '\n');
+      line[rd - 1] = '\0';
+      success = p->AddLine(line);
+    }
+  } while (rd > 1 && success);
+  free(line);
+  return success;
+}
+}  // namespace
+
+int DeobfuscateProfile(std::istream* input, std::ostream* output) {
+  base::ignore_result(input);
+  base::ignore_result(output);
+  auto maybe_map = GetPerfettoProguardMapPath();
+  if (!maybe_map) {
+    PERFETTO_ELOG("No PERFETTO_PROGUARD_MAP specified.");
+    return 1;
+  }
+  base::ScopedFstream f(fopen(maybe_map->c_str(), "r"));
+  if (!f) {
+    PERFETTO_ELOG("Failed to open %s", maybe_map->c_str());
+    return 1;
+  }
+  profiling::ProguardParser parser;
+  if (!ParseFile(&parser, *f)) {
+    PERFETTO_ELOG("Failed to parse %s", maybe_map->c_str());
+    return 1;
+  }
+  std::map<std::string, profiling::ObfuscatedClass> obfuscation_map =
+      parser.ConsumeMapping();
+
+  trace_processor::Config config;
+  std::unique_ptr<trace_processor::TraceProcessor> tp =
+      trace_processor::TraceProcessor::CreateInstance(config);
+
+  if (!ReadTrace(tp.get(), input))
+    PERFETTO_FATAL("Failed to read trace.");
+
+  tp->NotifyEndOfFile();
+  DeobfuscateDatabase(tp.get(), obfuscation_map,
+                      [output](const perfetto::protos::TracePacket& packet) {
+                        WriteTracePacket(packet.SerializeAsString(), output);
+                      });
+  return 0;
+}
+
+}  // namespace trace_to_text
+}  // namespace perfetto
diff --git a/tools/trace_to_text/deobfuscate_profile.h b/tools/trace_to_text/deobfuscate_profile.h
new file mode 100644
index 0000000..d5808c6
--- /dev/null
+++ b/tools/trace_to_text/deobfuscate_profile.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 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 TOOLS_TRACE_TO_TEXT_DEOBFUSCATE_PROFILE_H_
+#define TOOLS_TRACE_TO_TEXT_DEOBFUSCATE_PROFILE_H_
+
+#include <iostream>
+
+namespace perfetto {
+namespace trace_to_text {
+
+int DeobfuscateProfile(std::istream* input, std::ostream* output);
+
+}
+}  // namespace perfetto
+
+#endif  // TOOLS_TRACE_TO_TEXT_DEOBFUSCATE_PROFILE_H_
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc
index 223fc64..efcc053 100644
--- a/tools/trace_to_text/main.cc
+++ b/tools/trace_to_text/main.cc
@@ -21,6 +21,7 @@
 
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/string_utils.h"
+#include "tools/trace_to_text/deobfuscate_profile.h"
 #include "tools/trace_to_text/symbolize_profile.h"
 #include "tools/trace_to_text/trace_to_json.h"
 #include "tools/trace_to_text/trace_to_profile.h"
@@ -176,6 +177,8 @@
   if (format == "symbolize")
     return SymbolizeProfile(input_stream, output_stream);
 
+  if (format == "deobfuscate")
+    return DeobfuscateProfile(input_stream, output_stream);
   return Usage(argv[0]);
 }
 
diff --git a/tools/trace_to_text/symbolize_profile.cc b/tools/trace_to_text/symbolize_profile.cc
index 1d2812d..4ae59fb 100644
--- a/tools/trace_to_text/symbolize_profile.cc
+++ b/tools/trace_to_text/symbolize_profile.cc
@@ -31,22 +31,6 @@
 
 namespace perfetto {
 namespace trace_to_text {
-namespace {
-
-using ::protozero::proto_utils::kMessageLengthFieldSize;
-using ::protozero::proto_utils::MakeTagLengthDelimited;
-using ::protozero::proto_utils::WriteVarInt;
-
-void WriteTracePacket(const std::string& str, std::ostream* output) {
-  constexpr char kPreamble =
-      MakeTagLengthDelimited(protos::pbzero::Trace::kPacketFieldNumber);
-  uint8_t length_field[10];
-  uint8_t* end = WriteVarInt(str.size(), length_field);
-  *output << kPreamble;
-  *output << std::string(length_field, end);
-  *output << str;
-}
-}
 
 // Ingest profile, and emit a symbolization table for each sequence. This can
 // be prepended to the profile to attach the symbol information.
diff --git a/tools/trace_to_text/utils.cc b/tools/trace_to_text/utils.cc
index 5055b98..a523e2a 100644
--- a/tools/trace_to_text/utils.cc
+++ b/tools/trace_to_text/utils.cc
@@ -21,6 +21,7 @@
 
 #include <memory>
 #include <ostream>
+#include <set>
 #include <utility>
 
 #include "perfetto/base/logging.h"
@@ -29,6 +30,7 @@
 #include "protos/perfetto/trace/ftrace/ftrace_stats.pb.h"
 
 #include "protos/perfetto/trace/trace.pb.h"
+#include "protos/perfetto/trace/trace.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pb.h"
 
 namespace perfetto {
@@ -92,8 +94,51 @@
   return res;
 }
 
+std::map<std::string, std::set<std::string>> GetHeapGraphClasses(
+    trace_processor::TraceProcessor* tp) {
+  std::map<std::string, std::set<std::string>> res;
+  Iterator it = tp->ExecuteQuery("select type_name from heap_graph_object");
+  while (it.Next())
+    res.emplace(it.Get(0).string_value, std::set<std::string>());
+
+  PERFETTO_CHECK(it.Status().ok());
+
+  it = tp->ExecuteQuery("select field_name from heap_graph_reference");
+  while (it.Next()) {
+    std::string field_name = it.Get(0).string_value;
+    if (field_name.size() == 0)
+      continue;
+    size_t n = field_name.rfind(".");
+    if (n == std::string::npos || n == field_name.size() - 1) {
+      PERFETTO_ELOG("Invalid field name: %s", field_name.c_str());
+      continue;
+    }
+    std::string class_name = field_name;
+    class_name.resize(n);
+    field_name = field_name.substr(n + 1);
+    res[class_name].emplace(field_name);
+  }
+
+  PERFETTO_CHECK(it.Status().ok());
+  return res;
+}
+
+using ::protozero::proto_utils::kMessageLengthFieldSize;
+using ::protozero::proto_utils::MakeTagLengthDelimited;
+using ::protozero::proto_utils::WriteVarInt;
+
 }  // namespace
 
+void WriteTracePacket(const std::string& str, std::ostream* output) {
+  constexpr char kPreamble =
+      MakeTagLengthDelimited(protos::pbzero::Trace::kPacketFieldNumber);
+  uint8_t length_field[10];
+  uint8_t* end = WriteVarInt(str.size(), length_field);
+  *output << kPreamble;
+  *output << std::string(length_field, end);
+  *output << str;
+}
+
 void ForEachPacketBlobInTrace(
     std::istream* input,
     const std::function<void(std::unique_ptr<char[]>, size_t)>& f) {
@@ -165,6 +210,14 @@
   return roots;
 }
 
+base::Optional<std::string> GetPerfettoProguardMapPath() {
+  base::Optional<std::string> proguard_map;
+  const char* env = getenv("PERFETTO_PROGUARD_MAP");
+  if (env != nullptr)
+    proguard_map = env;
+  return proguard_map;
+}
+
 bool ReadTrace(trace_processor::TraceProcessor* tp, std::istream* input) {
   // 1MB chunk size seems the best tradeoff on a MacBook Pro 2013 - i7 2.8 GHz.
   constexpr size_t kChunkSize = 1024 * 1024;
@@ -238,6 +291,46 @@
   }
 }
 
+void DeobfuscateDatabase(
+    trace_processor::TraceProcessor* tp,
+    const std::map<std::string, profiling::ObfuscatedClass>& mapping,
+    std::function<void(perfetto::protos::TracePacket)> callback) {
+  std::map<std::string, std::set<std::string>> classes =
+      GetHeapGraphClasses(tp);
+  perfetto::protos::TracePacket packet;
+  // TODO(fmayer): Add handling for package name and version code here so we
+  // can support multiple dumps in the same trace.
+  perfetto::protos::DeobfuscationMapping* proto_mapping =
+      packet.mutable_deobfuscation_mapping();
+  for (const auto& p : classes) {
+    const std::string& obfuscated_class_name = p.first;
+    const std::set<std::string>& obfuscated_field_names = p.second;
+    auto it = mapping.find(obfuscated_class_name);
+    if (it == mapping.end()) {
+      // This can happen for non-obfuscated class names. Do not log.
+      continue;
+    }
+    const profiling::ObfuscatedClass& cls = it->second;
+    perfetto::protos::ObfuscatedClass* proto_class =
+        proto_mapping->add_obfuscated_classes();
+    proto_class->set_obfuscated_name(obfuscated_class_name);
+    proto_class->set_deobfuscated_name(cls.deobfuscated_name);
+    for (const std::string& obfuscated_field_name : obfuscated_field_names) {
+      auto field_it = cls.deobfuscated_fields.find(obfuscated_field_name);
+      if (field_it != cls.deobfuscated_fields.end()) {
+        perfetto::protos::ObfuscatedMember* proto_member =
+            proto_class->add_obfuscated_members();
+        proto_member->set_obfuscated_name(obfuscated_field_name);
+        proto_member->set_deobfuscated_name(field_it->second);
+      } else {
+        PERFETTO_ELOG("%s.%s not found", obfuscated_class_name.c_str(),
+                      obfuscated_field_name.c_str());
+      }
+    }
+  }
+  callback(packet);
+}
+
 TraceWriter::TraceWriter(std::ostream* output) : output_(output) {}
 
 TraceWriter::~TraceWriter() = default;
diff --git a/tools/trace_to_text/utils.h b/tools/trace_to_text/utils.h
index f4004c3..9cc7c1f 100644
--- a/tools/trace_to_text/utils.h
+++ b/tools/trace_to_text/utils.h
@@ -29,7 +29,9 @@
 #include <zlib.h>
 
 #include "perfetto/base/build_config.h"
+#include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/paged_memory.h"
+#include "perfetto/profiling/deobfuscator.h"
 #include "perfetto/profiling/symbolizer.h"
 #include "perfetto/trace_processor/trace_processor.h"
 
@@ -58,14 +60,27 @@
     const std::function<void(const protos::TracePacket&)>&);
 
 std::vector<std::string> GetPerfettoBinaryPath();
+base::Optional<std::string> GetPerfettoProguardMapPath();
 
 bool ReadTrace(trace_processor::TraceProcessor* tp, std::istream* input);
 
+void WriteTracePacket(const std::string& str, std::ostream* output);
+
+// Generate ModuleSymbol protos for all unsymbolized frames in the database.
+// Wrap them in TracePackets and call callback.
 void SymbolizeDatabase(
     trace_processor::TraceProcessor* tp,
     Symbolizer* symbolizer,
     std::function<void(perfetto::protos::TracePacket)> callback);
 
+// Generate ObfuscationMapping protos for all obfuscated java names in the
+// database.
+// Wrap them in TracePackets and call callback.
+void DeobfuscateDatabase(
+    trace_processor::TraceProcessor* tp,
+    const std::map<std::string, profiling::ObfuscatedClass>& mapping,
+    std::function<void(perfetto::protos::TracePacket)> callback);
+
 class TraceWriter {
  public:
   TraceWriter(std::ostream* output);