Merge "Speculative fix of chromium roll"
diff --git a/Android.bp b/Android.bp
index 65bb922..2af83bc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4589,6 +4589,7 @@
     "src/trace_processor/fuchsia_trace_parser.cc",
     "src/trace_processor/fuchsia_trace_tokenizer.cc",
     "src/trace_processor/fuchsia_trace_utils.cc",
+    "src/trace_processor/graphics_frame_event_parser.cc",
     "src/trace_processor/gzip_trace_parser.cc",
     "src/trace_processor/heap_profile_allocation_table.cc",
     "src/trace_processor/heap_profile_tracker.cc",
@@ -4792,6 +4793,7 @@
     "src/trace_processor/fuchsia_trace_parser.cc",
     "src/trace_processor/fuchsia_trace_tokenizer.cc",
     "src/trace_processor/fuchsia_trace_utils.cc",
+    "src/trace_processor/graphics_frame_event_parser.cc",
     "src/trace_processor/gzip_trace_parser.cc",
     "src/trace_processor/heap_profile_allocation_table.cc",
     "src/trace_processor/heap_profile_tracker.cc",
diff --git a/BUILD b/BUILD
index d5f60a1..e62f1bb 100644
--- a/BUILD
+++ b/BUILD
@@ -345,6 +345,8 @@
         "src/trace_processor/fuchsia_trace_tokenizer.h",
         "src/trace_processor/fuchsia_trace_utils.cc",
         "src/trace_processor/fuchsia_trace_utils.h",
+        "src/trace_processor/graphics_frame_event_parser.cc",
+        "src/trace_processor/graphics_frame_event_parser.h",
         "src/trace_processor/gzip_trace_parser.cc",
         "src/trace_processor/gzip_trace_parser.h",
         "src/trace_processor/heap_profile_allocation_table.cc",
@@ -666,6 +668,8 @@
         "src/trace_processor/fuchsia_trace_tokenizer.h",
         "src/trace_processor/fuchsia_trace_utils.cc",
         "src/trace_processor/fuchsia_trace_utils.h",
+        "src/trace_processor/graphics_frame_event_parser.cc",
+        "src/trace_processor/graphics_frame_event_parser.h",
         "src/trace_processor/gzip_trace_parser.cc",
         "src/trace_processor/gzip_trace_parser.h",
         "src/trace_processor/heap_profile_allocation_table.cc",
@@ -937,6 +941,8 @@
         "src/trace_processor/fuchsia_trace_tokenizer.h",
         "src/trace_processor/fuchsia_trace_utils.cc",
         "src/trace_processor/fuchsia_trace_utils.h",
+        "src/trace_processor/graphics_frame_event_parser.cc",
+        "src/trace_processor/graphics_frame_event_parser.h",
         "src/trace_processor/gzip_trace_parser.cc",
         "src/trace_processor/gzip_trace_parser.h",
         "src/trace_processor/heap_profile_allocation_table.cc",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 0466cbe..abca975 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -76,6 +76,8 @@
     "fuchsia_trace_tokenizer.h",
     "fuchsia_trace_utils.cc",
     "fuchsia_trace_utils.h",
+    "graphics_frame_event_parser.cc",
+    "graphics_frame_event_parser.h",
     "gzip_trace_parser.cc",
     "gzip_trace_parser.h",
     "heap_profile_allocation_table.cc",
diff --git a/src/trace_processor/graphics_frame_event_parser.cc b/src/trace_processor/graphics_frame_event_parser.cc
new file mode 100644
index 0000000..70fde24
--- /dev/null
+++ b/src/trace_processor/graphics_frame_event_parser.cc
@@ -0,0 +1,151 @@
+/*
+ * 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/graphics_frame_event_parser.h"
+
+#include "perfetto/protozero/field.h"
+#include "perfetto/trace/android/graphics_frame_event.pbzero.h"
+#include "src/trace_processor/args_tracker.h"
+#include "src/trace_processor/slice_tracker.h"
+#include "src/trace_processor/trace_processor_context.h"
+#include "src/trace_processor/virtual_track_tracker.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+using BufferEventType = protos::pbzero::GraphicsFrameEvent_BufferEventType;
+using ConstBytes = protozero::ConstBytes;
+
+GraphicsFrameEventParser::~GraphicsFrameEventParser() = default;
+
+GraphicsFrameEventParser::GraphicsFrameEventParser(
+    TraceProcessorContext* context)
+    : context_(context),
+      graphics_event_scope_id_(
+          context->storage->InternString("graphics_frame_event.scope")),
+      unspecified_event_name_id_(
+          context->storage->InternString("unspecified_event")),
+      dequeue_name_id_(context->storage->InternString("Dequeue")),
+      queue_name_id_(context->storage->InternString("Queue")),
+      post_name_id_(context->storage->InternString("Post")),
+      acquire_name_id_(context->storage->InternString("AcquireFenceSignaled")),
+      latch_name_id_(context->storage->InternString("Latch")),
+      hwc_composition_queued_name_id_(
+          context->storage->InternString("HWCCompositionQueued")),
+      fallback_composition_name_id_(
+          context->storage->InternString("FallbackComposition")),
+      present_name_id_(context->storage->InternString("PresentFenceSignaled")),
+      release_name_id_(context->storage->InternString("ReleaseFenceSignaled")),
+      modify_name_id_(context->storage->InternString("Modify")),
+      unknown_event_name_id_(context->storage->InternString("unknown_event")),
+      no_layer_name_name_id_(context->storage->InternString("no_layer_name")),
+      layer_name_key_id_(context->storage->InternString("layer_name")),
+      frame_number_key_id_(context->storage->InternString("frame_number")),
+      event_type_name_ids_{
+          {unspecified_event_name_id_ /* UNSPECIFIED */,
+           dequeue_name_id_ /* DEQUEUE */, queue_name_id_ /* QUEUE */,
+           post_name_id_ /* POST */, acquire_name_id_ /* ACQUIRE_FENCE */,
+           latch_name_id_ /* LATCH */,
+           hwc_composition_queued_name_id_ /* HWC_COMPOSITION_QUEUED */,
+           fallback_composition_name_id_ /* FALLBACK_COMPOSITION */,
+           present_name_id_ /* PRESENT_FENCE */,
+           release_name_id_ /* RELEASE_FENCE */,
+           modify_name_id_ /* MODIFY */}} {}
+
+void GraphicsFrameEventParser::ParseEvent(int64_t timestamp, ConstBytes blob) {
+  protos::pbzero::GraphicsFrameEvent_Decoder frame_event(blob.data, blob.size);
+  if (!frame_event.has_buffer_event()) {
+    return;
+  }
+
+  ConstBytes bufferBlob = frame_event.buffer_event();
+  protos::pbzero::GraphicsFrameEvent_BufferEvent_Decoder event(bufferBlob.data,
+                                                               bufferBlob.size);
+
+  if (!event.has_buffer_id()) {
+    context_->storage->IncrementStats(stats::graphics_frame_event_parser_errors);
+    PERFETTO_ELOG("GraphicsFrameEvent with missing buffer id field.");
+    return;
+  }
+
+  StringId event_name_id = unknown_event_name_id_;
+  if (event.has_type()) {
+    const auto type = static_cast<size_t>(event.type());
+    if (type < event_type_name_ids_.size()) {
+      event_name_id = event_type_name_ids_[type];
+    } else {
+      context_->storage->IncrementStats(stats::graphics_frame_event_parser_errors);
+      PERFETTO_ELOG("GraphicsFrameEvent with unknown type %zu.", type);
+    }
+  } else {
+    context_->storage->IncrementStats(stats::graphics_frame_event_parser_errors);
+    PERFETTO_ELOG("GraphicsFrameEvent with missing type field.");
+  }
+
+  const uint32_t buffer_id = event.buffer_id();
+  StringId layer_name_id;
+
+  char buffer[4096];
+  const size_t layerNameMaxLength = 4000;
+  base::StringWriter track_name(buffer, sizeof(buffer));
+  if (event.has_layer_name()) {
+    const base::StringView layer_name(event.layer_name());
+    layer_name_id = context_->storage->InternString(layer_name);
+    track_name.AppendString(layer_name.substr(0, layerNameMaxLength));
+  } else {
+    layer_name_id = no_layer_name_name_id_;
+    track_name.AppendLiteral("unknown_layer");
+  }
+  track_name.AppendLiteral("[buffer:");
+  track_name.AppendUnsignedInt(buffer_id);
+  track_name.AppendChar(']');
+
+  const StringId track_name_id =
+      context_->storage->InternString(track_name.GetStringView());
+  const int64_t duration =
+      event.has_duration_ns() ? static_cast<int64_t>(event.duration_ns()) : 0;
+  const uint32_t frame_number =
+      event.has_frame_number() ? event.frame_number() : 0;
+
+  const TrackId track_id = context_->virtual_track_tracker->GetOrCreateTrack(
+      {VirtualTrackScope::kGlobal, 0 /* upid */, track_name_id,
+       graphics_event_scope_id_},
+      track_name_id);
+
+  // TODO(lalitm): These need to be swapped out for base::nullopt when supported.
+  constexpr uint64_t null_u64 = std::numeric_limits<uint64_t>::max();
+  constexpr uint32_t null_u32 = std::numeric_limits<uint32_t>::max();
+
+  context_->storage->mutable_gpu_tracks()->AddGpuTrack(
+      track_id, graphics_event_scope_id_, null_u64 /* context */);
+
+  const auto slice_id = context_->slice_tracker->Scoped(
+      timestamp, track_id, RefType::kRefTrack, 0 /* cat */, event_name_id,
+      duration, [this, layer_name_id](ArgsTracker* args_tracker, RowId row_id) {
+        args_tracker->AddArg(row_id, layer_name_key_id_, layer_name_key_id_,
+                             Variadic::String(layer_name_id));
+      });
+
+  if (slice_id) {
+    context_->storage->mutable_gpu_track_slices()->AddGpuSlice(
+        slice_id.value(), null_u64 /* context_id */,
+        null_u64 /* render_target */, frame_number, null_u32 /* job_id */,
+        null_u32 /* hw_queue_id */);
+  }
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/graphics_frame_event_parser.h b/src/trace_processor/graphics_frame_event_parser.h
new file mode 100644
index 0000000..12ae908
--- /dev/null
+++ b/src/trace_processor/graphics_frame_event_parser.h
@@ -0,0 +1,63 @@
+/*
+ * 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_GRAPHICS_FRAME_EVENT_PARSER_H_
+#define SRC_TRACE_PROCESSOR_GRAPHICS_FRAME_EVENT_PARSER_H_
+
+#include <vector>
+
+#include "perfetto/protozero/field.h"
+#include "src/trace_processor/trace_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+// Class for parsing GraphicFrameEvents.
+class GraphicsFrameEventParser {
+ public:
+  explicit GraphicsFrameEventParser(TraceProcessorContext*);
+  ~GraphicsFrameEventParser();
+
+  void ParseEvent(int64_t timestamp, protozero::ConstBytes);
+
+ private:
+  TraceProcessorContext* const context_;
+  const StringId graphics_event_scope_id_;
+  const StringId unspecified_event_name_id_;
+  const StringId dequeue_name_id_;
+  const StringId queue_name_id_;
+  const StringId post_name_id_;
+  const StringId acquire_name_id_;
+  const StringId latch_name_id_;
+  const StringId hwc_composition_queued_name_id_;
+  const StringId fallback_composition_name_id_;
+  const StringId present_name_id_;
+  const StringId release_name_id_;
+  const StringId modify_name_id_;
+  const StringId unknown_event_name_id_;
+  const StringId no_layer_name_name_id_;
+  const StringId layer_name_key_id_;
+  const StringId frame_number_key_id_;
+
+  std::array<StringId, 11> event_type_name_ids_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_GRAPHICS_FRAME_EVENT_PARSER_H_
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index fc552df..b288155 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -213,6 +213,7 @@
 
 ProtoTraceParser::ProtoTraceParser(TraceProcessorContext* context)
     : context_(context),
+      graphics_frame_event_parser_(new GraphicsFrameEventParser(context_)),
       utid_name_id_(context->storage->InternString("utid")),
       sched_wakeup_name_id_(context->storage->InternString("sched_wakeup")),
       sched_waking_name_id_(context->storage->InternString("sched_waking")),
@@ -462,6 +463,10 @@
     ParseAndroidPackagesList(packet.packages_list());
   }
 
+  if (packet.has_graphics_frame_event()) {
+    graphics_frame_event_parser_->ParseEvent(ts, packet.graphics_frame_event());
+  }
+
   // TODO(lalitm): maybe move this to the flush method in the trace processor
   // once we have it. This may reduce performance in the ArgsTracker though so
   // needs to be handled carefully.
diff --git a/src/trace_processor/proto_trace_parser.h b/src/trace_processor/proto_trace_parser.h
index 52e416a..9e20af0 100644
--- a/src/trace_processor/proto_trace_parser.h
+++ b/src/trace_processor/proto_trace_parser.h
@@ -25,6 +25,7 @@
 #include "perfetto/ext/base/string_view.h"
 #include "perfetto/protozero/field.h"
 #include "src/trace_processor/ftrace_descriptors.h"
+#include "src/trace_processor/graphics_frame_event_parser.h"
 #include "src/trace_processor/proto_incremental_state.h"
 #include "src/trace_processor/slice_tracker.h"
 #include "src/trace_processor/trace_blob_view.h"
@@ -143,6 +144,8 @@
 
  private:
   TraceProcessorContext* context_;
+  std::unique_ptr<GraphicsFrameEventParser> graphics_frame_event_parser_;
+
   const StringId utid_name_id_;
   const StringId sched_wakeup_name_id_;
   const StringId sched_waking_name_id_;
diff --git a/src/trace_processor/stats.h b/src/trace_processor/stats.h
index d293a47..b9d3fe7 100644
--- a/src/trace_processor/stats.h
+++ b/src/trace_processor/stats.h
@@ -52,6 +52,7 @@
   F(fuchsia_timestamp_overflow,               kSingle,  kError,    kAnalysis), \
   F(gpu_counters_invalid_spec,                kSingle,  kError,    kAnalysis), \
   F(gpu_counters_missing_spec,                kSingle,  kError,    kAnalysis), \
+  F(graphics_frame_event_parser_errors,       kSingle,  kInfo,     kAnalysis), \
   F(guess_trace_type_duration_ns,             kSingle,  kInfo,     kAnalysis), \
   F(interned_data_tokenizer_errors,           kSingle,  kInfo,     kAnalysis), \
   F(invalid_clock_snapshots,                  kSingle,  kError,    kAnalysis), \
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index d88b0b0..64918ff 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -1254,6 +1254,9 @@
     return &virtual_track_slices_;
   }
 
+  const GpuSlices& gpu_track_slices() const { return gpu_track_slices_; }
+  GpuSlices* mutable_gpu_track_slices() { return &gpu_track_slices_; }
+
   const CounterDefinitions& counter_definitions() const {
     return counter_definitions_;
   }
@@ -1312,6 +1315,9 @@
     return &heap_profile_allocations_;
   }
 
+  const GpuTracks& gpu_tracks() const { return gpu_tracks_; }
+  GpuTracks* mutable_gpu_tracks() { return &gpu_tracks_; }
+
   const StringPool& string_pool() const { return string_pool_; }
 
   // |unique_processes_| always contains at least 1 element becuase the 0th ID
diff --git a/test/synth_common.py b/test/synth_common.py
index 2cad299..0a4efe2 100644
--- a/test/synth_common.py
+++ b/test/synth_common.py
@@ -254,6 +254,17 @@
     gpu_counter.counter_id = counter_id
     gpu_counter.int_value = value
 
+  def add_buffer_event_packet(self, ts, buffer_id, layer_name, frame_number, event_type, duration):
+    packet = self.add_packet()
+    packet.timestamp = ts
+    buffer_event = packet.graphics_frame_event.buffer_event
+    if buffer_id >= 0:
+      buffer_event.buffer_id = buffer_id
+    buffer_event.layer_name = layer_name
+    buffer_event.frame_number = frame_number
+    if event_type >= 0:
+      buffer_event.type = event_type
+    buffer_event.duration_ns = duration
 
 def create_trace():
   parser = argparse.ArgumentParser()
diff --git a/test/trace_processor/graphics_frame_events.out b/test/trace_processor/graphics_frame_events.out
new file mode 100644
index 0000000..680dd59
--- /dev/null
+++ b/test/trace_processor/graphics_frame_events.out
@@ -0,0 +1,7 @@
+"ts","dur","name","key","layer_name"
+1,6,"Dequeue","layer_name","layerName1"
+2,7,"Queue","layer_name","layerName2"
+3,8,"Post","layer_name","layerName3"
+4,9,"AcquireFenceSignaled","layer_name","layerName4"
+5,10,"Latch","layer_name","layerName5"
+7,12,"unknown_event","layer_name","layerName7"
diff --git a/test/trace_processor/graphics_frame_events.py b/test/trace_processor/graphics_frame_events.py
new file mode 100755
index 0000000..1c3ee94
--- /dev/null
+++ b/test/trace_processor/graphics_frame_events.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+# 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.
+
+from os import sys, path
+sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
+import synth_common
+
+trace = synth_common.create_trace()
+trace.add_buffer_event_packet(ts=1, buffer_id=1, layer_name="layerName1", frame_number=1, event_type=1, duration=6)
+trace.add_buffer_event_packet(ts=2, buffer_id=2, layer_name="layerName2", frame_number=2, event_type=2, duration=7)
+trace.add_buffer_event_packet(ts=3, buffer_id=3, layer_name="layerName3", frame_number=3, event_type=3, duration=8)
+trace.add_buffer_event_packet(ts=4, buffer_id=4, layer_name="layerName4", frame_number=4, event_type=4, duration=9)
+trace.add_buffer_event_packet(ts=5, buffer_id=5, layer_name="layerName5", frame_number=5, event_type=5, duration=10)
+# Missing id.
+trace.add_buffer_event_packet(ts=6, buffer_id=-1, layer_name="layerName6", frame_number=6, event_type=6, duration=11)
+# Missing type.
+trace.add_buffer_event_packet(ts=7, buffer_id=7, layer_name="layerName7", frame_number=7, event_type=-1, duration=12)
+
+print(trace.trace.SerializeToString())
diff --git a/test/trace_processor/graphics_frame_events.sql b/test/trace_processor/graphics_frame_events.sql
new file mode 100644
index 0000000..c31319b
--- /dev/null
+++ b/test/trace_processor/graphics_frame_events.sql
@@ -0,0 +1,4 @@
+select ts, dur, name, key, string_value as layer_name
+from internal_slice
+left join args
+on internal_slice.arg_set_id=args.arg_set_id and (args.key='layer_name')
diff --git a/test/trace_processor/index b/test/trace_processor/index
index 493534c..4dbac87 100644
--- a/test/trace_processor/index
+++ b/test/trace_processor/index
@@ -110,9 +110,12 @@
 # Unsigned integers
 print_systrace_unsigned.py print_systrace.sql print_systrace_unsigned.out
 
-# GPU trace tests
+# GPU trace tests.
 ../data/gpu_counters.pb gpu_counters.sql gpu_counters.out
 ../data/gpu_trace.pb gpu_render_stages.sql gpu_render_stages.out
 
 # Clock sync
 clock_sync.py clock_sync.sql clock_sync.out
+
+# Graphics frame event trace tests.
+graphics_frame_events.py graphics_frame_events.sql graphics_frame_events.out