traceconv: niche decompress_packets option for rewriting a trace as if compressed_packets were written normally

I find myself wanting to convert the size breakdown of such traces to
pprof flamecharts once in a while, hence this helper.
The experimental proto path analysis in trace_processor already
understands compressed packets, but isn't as easy to get a pprof out of.

Change-Id: I3f203a591008e4078488f6acb89800beaf0e1055
diff --git a/Android.bp b/Android.bp
index a4b4894..636459a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12456,6 +12456,7 @@
         "src/traceconv/trace_to_profile.cc",
         "src/traceconv/trace_to_systrace.cc",
         "src/traceconv/trace_to_text.cc",
+        "src/traceconv/trace_unpack.cc",
     ],
 }
 
diff --git a/BUILD b/BUILD
index fe8598c..1399366 100644
--- a/BUILD
+++ b/BUILD
@@ -2918,6 +2918,8 @@
         "src/traceconv/trace_to_systrace.h",
         "src/traceconv/trace_to_text.cc",
         "src/traceconv/trace_to_text.h",
+        "src/traceconv/trace_unpack.cc",
+        "src/traceconv/trace_unpack.h",
     ],
 )
 
diff --git a/src/traceconv/BUILD.gn b/src/traceconv/BUILD.gn
index 97c7524..8cde4f4 100644
--- a/src/traceconv/BUILD.gn
+++ b/src/traceconv/BUILD.gn
@@ -108,6 +108,8 @@
     "trace_to_text.cc",
     "trace_to_text.h",
     "trace_to_text.h",
+    "trace_unpack.cc",
+    "trace_unpack.h",
   ]
 }
 
diff --git a/src/traceconv/main.cc b/src/traceconv/main.cc
index 1570281..d7e6ac4 100644
--- a/src/traceconv/main.cc
+++ b/src/traceconv/main.cc
@@ -31,6 +31,7 @@
 #include "src/traceconv/trace_to_profile.h"
 #include "src/traceconv/trace_to_systrace.h"
 #include "src/traceconv/trace_to_text.h"
+#include "src/traceconv/trace_unpack.h"
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 #include <fcntl.h>
@@ -47,7 +48,8 @@
   fprintf(stderr,
           "Usage: %s MODE [OPTIONS] [input file] [output file]\n"
           "modes:\n"
-          "  systrace|json|ctrace|text|profile|hprof|symbolize|deobfuscate\n"
+          "  systrace|json|ctrace|text|profile|hprof|symbolize|deobfuscate"
+          "|decompress_packets\n"
           "options:\n"
           "  [--truncate start|end]\n"
           "  [--full-sort]\n"
@@ -186,13 +188,15 @@
 
   if (truncate_keep != Keep::kAll) {
     PERFETTO_ELOG(
-        "--truncate is unsupported for text|profile|symbolize format.");
+        "--truncate is unsupported for "
+        "text|profile|symbolize|decompress_packets format.");
     return 1;
   }
 
   if (full_sort) {
     PERFETTO_ELOG(
-        "--full-sort is unsupported for text|profile|symbolize format.");
+        "--full-sort is unsupported for "
+        "text|profile|symbolize|decompress_packets format.");
     return 1;
   }
 
@@ -216,6 +220,10 @@
 
   if (format == "deobfuscate")
     return DeobfuscateProfile(input_stream, output_stream);
+
+  if (format == "decompress_packets")
+    return UnpackCompressedPackets(input_stream, output_stream);
+
   return Usage(argv[0]);
 }
 
diff --git a/src/traceconv/trace_unpack.cc b/src/traceconv/trace_unpack.cc
new file mode 100644
index 0000000..060a7b2
--- /dev/null
+++ b/src/traceconv/trace_unpack.cc
@@ -0,0 +1,47 @@
+/*
+ * 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/traceconv/trace_unpack.h"
+
+#include <iostream>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "perfetto/trace_processor/read_trace.h"
+#include "src/traceconv/utils.h"
+
+namespace perfetto {
+namespace trace_to_text {
+
+// Naive: puts multiple copies of the trace in memory, but good enough for
+// manual workflows.
+bool UnpackCompressedPackets(std::istream* input, std::ostream* output) {
+  std::vector<char> packed(std::istreambuf_iterator<char>{*input},
+                           std::istreambuf_iterator<char>{});
+  std::vector<uint8_t> unpacked;
+  auto status = trace_processor::DecompressTrace(
+      reinterpret_cast<uint8_t*>(packed.data()), packed.size(), &unpacked);
+  if (!status.ok())
+    return false;
+
+  TraceWriter trace_writer(output);
+  trace_writer.Write(reinterpret_cast<char*>(unpacked.data()), unpacked.size());
+  return true;
+}
+
+}  // namespace trace_to_text
+}  // namespace perfetto
diff --git a/src/traceconv/trace_unpack.h b/src/traceconv/trace_unpack.h
new file mode 100644
index 0000000..00e2537
--- /dev/null
+++ b/src/traceconv/trace_unpack.h
@@ -0,0 +1,32 @@
+/*
+ * 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_TRACECONV_TRACE_UNPACK_H_
+#define SRC_TRACECONV_TRACE_UNPACK_H_
+
+#include <iostream>
+
+namespace perfetto {
+namespace trace_to_text {
+
+// Serialised trace with compressed_packets -> serialised trace with those
+// packets in their decompressed form. Mostly for use with protoprofile.
+bool UnpackCompressedPackets(std::istream* input, std::ostream* output);
+
+}  // namespace trace_to_text
+}  // namespace perfetto
+
+#endif  // SRC_TRACECONV_TRACE_UNPACK_H_