Merge "Parse gzip'ed traces"
diff --git a/Android.bp b/Android.bp
index 7be3725..a4b5fe5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3731,6 +3731,7 @@
     "src/trace_processor/counter_values_table.cc",
     "src/trace_processor/event_tracker.cc",
     "src/trace_processor/filtered_row_index.cc",
+    "src/trace_processor/forwarding_trace_parser.cc",
     "src/trace_processor/ftrace_descriptors.cc",
     "src/trace_processor/ftrace_utils.cc",
     "src/trace_processor/fuchsia_provider_view.cc",
@@ -3902,6 +3903,7 @@
     "src/trace_processor/counter_values_table.cc",
     "src/trace_processor/event_tracker.cc",
     "src/trace_processor/filtered_row_index.cc",
+    "src/trace_processor/forwarding_trace_parser.cc",
     "src/trace_processor/ftrace_descriptors.cc",
     "src/trace_processor/ftrace_utils.cc",
     "src/trace_processor/fuchsia_provider_view.cc",
diff --git a/BUILD b/BUILD
index 144c09f..6703ee1 100644
--- a/BUILD
+++ b/BUILD
@@ -299,6 +299,8 @@
         "src/trace_processor/export_json.h",
         "src/trace_processor/filtered_row_index.cc",
         "src/trace_processor/filtered_row_index.h",
+        "src/trace_processor/forwarding_trace_parser.cc",
+        "src/trace_processor/forwarding_trace_parser.h",
         "src/trace_processor/ftrace_descriptors.cc",
         "src/trace_processor/ftrace_descriptors.h",
         "src/trace_processor/ftrace_utils.cc",
@@ -591,6 +593,8 @@
         "src/trace_processor/export_json.h",
         "src/trace_processor/filtered_row_index.cc",
         "src/trace_processor/filtered_row_index.h",
+        "src/trace_processor/forwarding_trace_parser.cc",
+        "src/trace_processor/forwarding_trace_parser.h",
         "src/trace_processor/ftrace_descriptors.cc",
         "src/trace_processor/ftrace_descriptors.h",
         "src/trace_processor/ftrace_utils.cc",
@@ -835,6 +839,8 @@
         "src/trace_processor/export_json.h",
         "src/trace_processor/filtered_row_index.cc",
         "src/trace_processor/filtered_row_index.h",
+        "src/trace_processor/forwarding_trace_parser.cc",
+        "src/trace_processor/forwarding_trace_parser.h",
         "src/trace_processor/ftrace_descriptors.cc",
         "src/trace_processor/ftrace_descriptors.h",
         "src/trace_processor/ftrace_utils.cc",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index ef0d92f..e7b4a97 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -63,6 +63,8 @@
     "event_tracker.h",
     "filtered_row_index.cc",
     "filtered_row_index.h",
+    "forwarding_trace_parser.cc",
+    "forwarding_trace_parser.h",
     "ftrace_descriptors.cc",
     "ftrace_descriptors.h",
     "ftrace_utils.cc",
@@ -237,6 +239,7 @@
     "clock_tracker_unittest.cc",
     "event_tracker_unittest.cc",
     "filtered_row_index_unittest.cc",
+    "forwarding_trace_parser_unittest.cc",
     "ftrace_utils_unittest.cc",
     "fuchsia_trace_utils_unittest.cc",
     "heap_profile_tracker_unittest.cc",
@@ -254,7 +257,6 @@
     "syscall_tracker_unittest.cc",
     "systrace_parser_unittest.cc",
     "thread_table_unittest.cc",
-    "trace_processor_impl_unittest.cc",
     "trace_sorter_unittest.cc",
   ]
   deps = [
diff --git a/src/trace_processor/forwarding_trace_parser.cc b/src/trace_processor/forwarding_trace_parser.cc
new file mode 100644
index 0000000..ca657f8
--- /dev/null
+++ b/src/trace_processor/forwarding_trace_parser.cc
@@ -0,0 +1,164 @@
+/*
+ * 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 "src/trace_processor/forwarding_trace_parser.h"
+
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/fuchsia_trace_parser.h"
+#include "src/trace_processor/fuchsia_trace_tokenizer.h"
+#include "src/trace_processor/gzip_trace_parser.h"
+#include "src/trace_processor/proto_trace_parser.h"
+#include "src/trace_processor/proto_trace_tokenizer.h"
+#include "src/trace_processor/systrace_trace_parser.h"
+
+// JSON parsing and exporting is only supported in the standalone and
+// Chromium builds.
+#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) || \
+    PERFETTO_BUILD_WITH_CHROMIUM
+#include "src/trace_processor/json_trace_parser.h"
+#include "src/trace_processor/json_trace_tokenizer.h"
+#endif
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+std::string RemoveWhitespace(const std::string& input) {
+  std::string str(input);
+  str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
+  return str;
+}
+
+// Fuchsia traces have a magic number as documented here:
+// https://fuchsia.googlesource.com/fuchsia/+/HEAD/docs/development/tracing/trace-format/README.md#magic-number-record-trace-info-type-0
+constexpr uint64_t kFuchsiaMagicNumber = 0x0016547846040010;
+
+}  // namespace
+
+ForwardingTraceParser::ForwardingTraceParser(TraceProcessorContext* context)
+    : context_(context) {}
+
+ForwardingTraceParser::~ForwardingTraceParser() {}
+
+util::Status ForwardingTraceParser::Parse(std::unique_ptr<uint8_t[]> data,
+                                          size_t size) {
+  // If this is the first Parse() call, guess the trace type and create the
+  // appropriate parser.
+
+  if (!reader_) {
+    TraceType trace_type;
+    {
+      auto scoped_trace = context_->storage->TraceExecutionTimeIntoStats(
+          stats::guess_trace_type_duration_ns);
+      trace_type = GuessTraceType(data.get(), size);
+    }
+    switch (trace_type) {
+      case kJsonTraceType: {
+        PERFETTO_DLOG("JSON trace detected");
+#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) || \
+    PERFETTO_BUILD_WITH_CHROMIUM
+        reader_.reset(new JsonTraceTokenizer(context_));
+        // JSON traces have no guarantees about the order of events in them.
+        int64_t window_size_ns = std::numeric_limits<int64_t>::max();
+        context_->sorter.reset(new TraceSorter(context_, window_size_ns));
+        context_->parser.reset(new JsonTraceParser(context_));
+#else
+        PERFETTO_FATAL("JSON traces not supported.");
+#endif
+        break;
+      }
+      case kProtoTraceType: {
+        PERFETTO_DLOG("Proto trace detected");
+        // This will be reduced once we read the trace config and we see flush
+        // period being set.
+        int64_t window_size_ns = std::numeric_limits<int64_t>::max();
+        reader_.reset(new ProtoTraceTokenizer(context_));
+        context_->sorter.reset(new TraceSorter(context_, window_size_ns));
+        context_->parser.reset(new ProtoTraceParser(context_));
+        break;
+      }
+      case kFuchsiaTraceType: {
+        PERFETTO_DLOG("Fuchsia trace detected");
+        // Fuschia traces can have massively out of order events.
+        int64_t window_size_ns = std::numeric_limits<int64_t>::max();
+        reader_.reset(new FuchsiaTraceTokenizer(context_));
+        context_->sorter.reset(new TraceSorter(context_, window_size_ns));
+        context_->parser.reset(new FuchsiaTraceParser(context_));
+        break;
+      }
+      case kSystraceTraceType:
+        PERFETTO_DLOG("Systrace trace detected");
+        reader_.reset(new SystraceTraceParser(context_));
+        break;
+      case kGzipTraceType:
+        PERFETTO_DLOG("gzip trace detected");
+        reader_.reset(new GzipTraceParser(context_));
+        break;
+      case kCtraceTraceType:
+        PERFETTO_DLOG("ctrace trace detected");
+        reader_.reset(new GzipTraceParser(context_));
+        break;
+      case kUnknownTraceType:
+        return util::ErrStatus("Unknown trace type provided");
+    }
+  }
+
+  return reader_->Parse(std::move(data), size);
+}
+
+TraceType GuessTraceType(const uint8_t* data, size_t size) {
+  if (size == 0)
+    return kUnknownTraceType;
+  std::string start(reinterpret_cast<const char*>(data),
+                    std::min<size_t>(size, 20));
+  std::string start_minus_white_space = RemoveWhitespace(start);
+  if (base::StartsWith(start_minus_white_space, "{\"traceEvents\":["))
+    return kJsonTraceType;
+  if (base::StartsWith(start_minus_white_space, "[{"))
+    return kJsonTraceType;
+  if (size >= 8) {
+    uint64_t first_word = *reinterpret_cast<const uint64_t*>(data);
+    if (first_word == kFuchsiaMagicNumber)
+      return kFuchsiaTraceType;
+  }
+
+  // Systrace with header but no leading HTML.
+  if (base::StartsWith(start, "# tracer"))
+    return kSystraceTraceType;
+
+  // Systrace with leading HTML.
+  if (base::StartsWith(start, "<!DOCTYPE html>") ||
+      base::StartsWith(start, "<html>"))
+    return kSystraceTraceType;
+
+  // Systrace with no header or leading HTML.
+  if (base::StartsWith(start, " "))
+    return kSystraceTraceType;
+
+  // Ctrace is deflate'ed systrace.
+  if (base::StartsWith(start, "TRACE:"))
+    return kCtraceTraceType;
+
+  // gzip'ed trace containing one of the other formats.
+  if (base::StartsWith(start, "\x1f\x8b"))
+    return kGzipTraceType;
+
+  return kProtoTraceType;
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/forwarding_trace_parser.h b/src/trace_processor/forwarding_trace_parser.h
new file mode 100644
index 0000000..f7216b3
--- /dev/null
+++ b/src/trace_processor/forwarding_trace_parser.h
@@ -0,0 +1,55 @@
+/*
+ * 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 SRC_TRACE_PROCESSOR_FORWARDING_TRACE_PARSER_H_
+#define SRC_TRACE_PROCESSOR_FORWARDING_TRACE_PARSER_H_
+
+#include "src/trace_processor/chunked_trace_reader.h"
+
+#include "src/trace_processor/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+enum TraceType {
+  kUnknownTraceType,
+  kProtoTraceType,
+  kJsonTraceType,
+  kFuchsiaTraceType,
+  kSystraceTraceType,
+  kGzipTraceType,
+  kCtraceTraceType,
+};
+
+TraceType GuessTraceType(const uint8_t* data, size_t size);
+
+class ForwardingTraceParser : public ChunkedTraceReader {
+ public:
+  explicit ForwardingTraceParser(TraceProcessorContext*);
+  ~ForwardingTraceParser() override;
+
+  // ChunkedTraceReader implementation
+  util::Status Parse(std::unique_ptr<uint8_t[]>, size_t) override;
+
+ private:
+  TraceProcessorContext* const context_;
+  std::unique_ptr<ChunkedTraceReader> reader_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_FORWARDING_TRACE_PARSER_H_
diff --git a/src/trace_processor/trace_processor_impl_unittest.cc b/src/trace_processor/forwarding_trace_parser_unittest.cc
similarity index 96%
rename from src/trace_processor/trace_processor_impl_unittest.cc
rename to src/trace_processor/forwarding_trace_parser_unittest.cc
index 24611d0..df4c013 100644
--- a/src/trace_processor/trace_processor_impl_unittest.cc
+++ b/src/trace_processor/forwarding_trace_parser_unittest.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/trace_processor_impl.h"
+#include "src/trace_processor/forwarding_trace_parser.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
diff --git a/src/trace_processor/gzip_trace_parser.cc b/src/trace_processor/gzip_trace_parser.cc
index 7b93af9..a374019 100644
--- a/src/trace_processor/gzip_trace_parser.cc
+++ b/src/trace_processor/gzip_trace_parser.cc
@@ -18,7 +18,8 @@
 
 #include <zlib.h>
 
-#include "src/trace_processor/systrace_trace_parser.h"
+#include "perfetto/base/logging.h"
+#include "src/trace_processor/forwarding_trace_parser.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -28,7 +29,7 @@
   z_stream_->zalloc = Z_NULL;
   z_stream_->zfree = Z_NULL;
   z_stream_->opaque = Z_NULL;
-  inflateInit(z_stream_.get());
+  inflateInit2(z_stream_.get(), 32 + 15);
 }
 
 GzipTraceParser::~GzipTraceParser() {
@@ -41,13 +42,17 @@
   uint8_t* start = data.get();
   size_t len = size;
 
-  static const char kSystraceFilerHeader[] = "TRACE:\n";
   if (!inner_) {
-    inner_.reset(new SystraceTraceParser(context_));
+    inner_.reset(new ForwardingTraceParser(context_));
 
-    // Strip the header by ignoring the associated bytes.
-    start += strlen(kSystraceFilerHeader);
-    len -= strlen(kSystraceFilerHeader);
+    // .ctrace files begin with "TRACE:" strip this if present.
+    static const char kSystraceFileHeader[] = "TRACE:\n";
+    if (size >= strlen(kSystraceFileHeader) &&
+        strncmp(reinterpret_cast<char*>(start), kSystraceFileHeader,
+                strlen(kSystraceFileHeader)) == 0) {
+      start += strlen(kSystraceFileHeader);
+      len -= strlen(kSystraceFileHeader);
+    }
   }
 
   z_stream_->next_in = start;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 710c770..70f18d2 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -33,9 +33,7 @@
 #include "src/trace_processor/counter_definitions_table.h"
 #include "src/trace_processor/counter_values_table.h"
 #include "src/trace_processor/event_tracker.h"
-#include "src/trace_processor/fuchsia_trace_parser.h"
-#include "src/trace_processor/fuchsia_trace_tokenizer.h"
-#include "src/trace_processor/gzip_trace_parser.h"
+#include "src/trace_processor/forwarding_trace_parser.h"
 #include "src/trace_processor/heap_profile_allocation_table.h"
 #include "src/trace_processor/heap_profile_callsite_table.h"
 #include "src/trace_processor/heap_profile_frame_table.h"
@@ -49,7 +47,6 @@
 #include "src/trace_processor/metrics/sql_metrics.h"
 #include "src/trace_processor/process_table.h"
 #include "src/trace_processor/process_tracker.h"
-#include "src/trace_processor/proto_trace_parser.h"
 #include "src/trace_processor/proto_trace_tokenizer.h"
 #include "src/trace_processor/raw_table.h"
 #include "src/trace_processor/sched_slice_table.h"
@@ -77,8 +74,6 @@
 #if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) || \
     PERFETTO_BUILD_WITH_CHROMIUM
 #include "src/trace_processor/export_json.h"
-#include "src/trace_processor/json_trace_parser.h"
-#include "src/trace_processor/json_trace_tokenizer.h"
 #endif
 
 // In Android and Chromium tree builds, we don't have the percentile module.
@@ -94,12 +89,6 @@
 namespace trace_processor {
 namespace {
 
-std::string RemoveWhitespace(const std::string& input) {
-  std::string str(input);
-  str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
-  return str;
-}
-
 void InitializeSqlite(sqlite3* db) {
   char* error = nullptr;
   sqlite3_exec(db, "PRAGMA temp_store=2", 0, 0, &error);
@@ -265,48 +254,8 @@
   }
 }
 
-// Fuchsia traces have a magic number as documented here:
-// https://fuchsia.googlesource.com/fuchsia/+/HEAD/docs/development/tracing/trace-format/README.md#magic-number-record-trace-info-type-0
-constexpr uint64_t kFuchsiaMagicNumber = 0x0016547846040010;
-
 }  // namespace
 
-TraceType GuessTraceType(const uint8_t* data, size_t size) {
-  if (size == 0)
-    return kUnknownTraceType;
-  std::string start(reinterpret_cast<const char*>(data),
-                    std::min<size_t>(size, 20));
-  std::string start_minus_white_space = RemoveWhitespace(start);
-  if (base::StartsWith(start_minus_white_space, "{\"traceEvents\":["))
-    return kJsonTraceType;
-  if (base::StartsWith(start_minus_white_space, "[{"))
-    return kJsonTraceType;
-  if (size >= 8) {
-    uint64_t first_word = *reinterpret_cast<const uint64_t*>(data);
-    if (first_word == kFuchsiaMagicNumber)
-      return kFuchsiaTraceType;
-  }
-
-  // Systrace with header but no leading HTML.
-  if (base::StartsWith(start, "# tracer"))
-    return kSystraceTraceType;
-
-  // Systrace with leading HTML.
-  if (base::StartsWith(start, "<!DOCTYPE html>") ||
-      base::StartsWith(start, "<html>"))
-    return kSystraceTraceType;
-
-  // Systrace with no header or leading HTML.
-  if (base::StartsWith(start, " "))
-    return kSystraceTraceType;
-
-  // Ctrace is GZIPed systrace with no headers.
-  if (base::StartsWith(start, "TRACE:"))
-    return kCtraceTraceType;
-
-  return kProtoTraceType;
-}
-
 TraceProcessorImpl::TraceProcessorImpl(const Config& cfg) {
   sqlite3* db = nullptr;
   PERFETTO_CHECK(sqlite3_initialize() == SQLITE_OK);
@@ -368,58 +317,8 @@
   if (unrecoverable_parse_error_)
     return util::ErrStatus(
         "Failed unrecoverably while parsing in a previous Parse call");
-
-  // If this is the first Parse() call, guess the trace type and create the
-  // appropriate parser.
-  if (!context_.chunk_reader) {
-    TraceType trace_type;
-    {
-      auto scoped_trace = context_.storage->TraceExecutionTimeIntoStats(
-          stats::guess_trace_type_duration_ns);
-      trace_type = GuessTraceType(data.get(), size);
-    }
-    switch (trace_type) {
-      case kJsonTraceType: {
-        PERFETTO_DLOG("Legacy JSON trace detected");
-#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) || \
-    PERFETTO_BUILD_WITH_CHROMIUM
-        context_.chunk_reader.reset(new JsonTraceTokenizer(&context_));
-        // JSON traces have no guarantees about the order of events in them.
-        int64_t window_size_ns = std::numeric_limits<int64_t>::max();
-        context_.sorter.reset(new TraceSorter(&context_, window_size_ns));
-        context_.parser.reset(new JsonTraceParser(&context_));
-#else
-        PERFETTO_FATAL("JSON traces not supported.");
-#endif
-        break;
-      }
-      case kProtoTraceType: {
-        // This will be reduced once we read the trace config and we see flush
-        // period being set.
-        int64_t window_size_ns = std::numeric_limits<int64_t>::max();
-        context_.chunk_reader.reset(new ProtoTraceTokenizer(&context_));
-        context_.sorter.reset(new TraceSorter(&context_, window_size_ns));
-        context_.parser.reset(new ProtoTraceParser(&context_));
-        break;
-      }
-      case kFuchsiaTraceType: {
-        // Fuschia traces can have massively out of order events.
-        int64_t window_size_ns = std::numeric_limits<int64_t>::max();
-        context_.chunk_reader.reset(new FuchsiaTraceTokenizer(&context_));
-        context_.sorter.reset(new TraceSorter(&context_, window_size_ns));
-        context_.parser.reset(new FuchsiaTraceParser(&context_));
-        break;
-      }
-      case kSystraceTraceType:
-        context_.chunk_reader.reset(new SystraceTraceParser(&context_));
-        break;
-      case kCtraceTraceType:
-        context_.chunk_reader.reset(new GzipTraceParser(&context_));
-        break;
-      case kUnknownTraceType:
-        return util::ErrStatus("Unknown trace type provided");
-    }
-  }
+  if (!context_.chunk_reader)
+    context_.chunk_reader.reset(new ForwardingTraceParser(&context_));
 
   auto scoped_trace = context_.storage->TraceExecutionTimeIntoStats(
       stats::parse_trace_duration_ns);
diff --git a/src/trace_processor/trace_processor_impl.h b/src/trace_processor/trace_processor_impl.h
index e9c3435..0ef2d7e 100644
--- a/src/trace_processor/trace_processor_impl.h
+++ b/src/trace_processor/trace_processor_impl.h
@@ -36,17 +36,6 @@
 
 namespace trace_processor {
 
-enum TraceType {
-  kUnknownTraceType,
-  kProtoTraceType,
-  kJsonTraceType,
-  kFuchsiaTraceType,
-  kSystraceTraceType,
-  kCtraceTraceType,
-};
-
-TraceType GuessTraceType(const uint8_t* data, size_t size);
-
 // Coordinates the loading of traces from an arbitrary source and allows
 // execution of SQL queries on the events in these traces.
 class TraceProcessorImpl : public TraceProcessor {