Merge "traced: prefer /run/perfetto for producer and consumer sockets on Linux"
diff --git a/src/trace_processor/importers/proto/graphics_frame_event_parser.cc b/src/trace_processor/importers/proto/graphics_frame_event_parser.cc
index e33ed9c..35e27f9 100644
--- a/src/trace_processor/importers/proto/graphics_frame_event_parser.cc
+++ b/src/trace_processor/importers/proto/graphics_frame_event_parser.cc
@@ -161,6 +161,31 @@
   return true;
 }
 
+void GraphicsFrameEventParser::InvalidatePhaseEvent(int64_t timestamp,
+                                                    TrackId track_id,
+                                                    bool reset_name) {
+  const auto opt_slice_id =
+      context_->slice_tracker->EndFrameEvent(timestamp, track_id);
+
+  if (opt_slice_id) {
+    auto* graphics_frame_slice_table =
+        context_->storage->mutable_graphics_frame_slice_table();
+    uint32_t row_idx = *graphics_frame_slice_table->id().IndexOf(*opt_slice_id);
+    if (reset_name) {
+      // Set the name (frame_number) to be 0 since there is no frame number
+      // associated, example : dequeue event.
+      StringId frame_name_id = context_->storage->InternString("0");
+      graphics_frame_slice_table->mutable_name()->Set(row_idx, frame_name_id);
+      graphics_frame_slice_table->mutable_frame_number()->Set(row_idx, 0);
+    }
+
+    // Set the duration to -1 so that this slice will be ignored by the
+    // UI. Setting any other duration results in wrong data which we want
+    // to avoid at all costs.
+    graphics_frame_slice_table->mutable_dur()->Set(row_idx, -1);
+  }
+}
+
 // Here we convert the buffer events into Phases(slices)
 // APP: Dequeue to Queue
 // Wait for GPU: Queue to Acquire
@@ -200,16 +225,29 @@
       tables::GpuTrackTable::Row app_track(track_name_id);
       app_track.scope = graphics_event_scope_id_;
       track_id = context_->track_tracker->InternGpuTrack(app_track);
+
+      // Error handling
+      auto dequeue_time = dequeue_map_.find(buffer_id);
+      if (dequeue_time != dequeue_map_.end()) {
+        InvalidatePhaseEvent(timestamp, dequeue_time->second, true);
+        dequeue_map_.erase(dequeue_time);
+      }
+      auto queue_time = queue_map_.find(buffer_id);
+      if (queue_time != queue_map_.end()) {
+        InvalidatePhaseEvent(timestamp, queue_time->second);
+        queue_map_.erase(queue_time);
+      }
+
       dequeue_map_[buffer_id] = track_id;
       last_dequeued_[buffer_id] = timestamp;
       break;
     }
 
     case GraphicsFrameEvent::QUEUE: {
-      auto dequeueTime = dequeue_map_.find(buffer_id);
-      if (dequeueTime != dequeue_map_.end()) {
+      auto dequeue_time = dequeue_map_.find(buffer_id);
+      if (dequeue_time != dequeue_map_.end()) {
         const auto opt_slice_id = context_->slice_tracker->EndFrameEvent(
-            timestamp, dequeueTime->second);
+            timestamp, dequeue_time->second);
         slice_name.reset();
         slice_name.AppendUnsignedInt(frame_number);
         if (opt_slice_id) {
@@ -225,7 +263,7 @@
                                                           frame_name_id);
           graphics_frame_slice_table->mutable_frame_number()->Set(row_idx,
                                                                   frame_number);
-          dequeue_map_.erase(dequeueTime);
+          dequeue_map_.erase(dequeue_time);
         }
       }
       // The AcquireFence might be signaled before receiving a QUEUE event
@@ -247,10 +285,10 @@
       break;
     }
     case GraphicsFrameEvent::ACQUIRE_FENCE: {
-      auto queueTime = queue_map_.find(buffer_id);
-      if (queueTime != queue_map_.end()) {
-        context_->slice_tracker->EndFrameEvent(timestamp, queueTime->second);
-        queue_map_.erase(queueTime);
+      auto queue_time = queue_map_.find(buffer_id);
+      if (queue_time != queue_map_.end()) {
+        context_->slice_tracker->EndFrameEvent(timestamp, queue_time->second);
+        queue_map_.erase(queue_time);
       }
       last_acquired_[buffer_id] = timestamp;
       start_slice = false;
@@ -259,31 +297,10 @@
     case GraphicsFrameEvent::LATCH: {
       // b/157578286 - Sometimes Queue event goes missing. To prevent having a
       // wrong slice info, we try to close any existing APP slice.
-      auto dequeueTime = dequeue_map_.find(buffer_id);
-      if (dequeueTime != dequeue_map_.end()) {
-        auto args_callback = [this](ArgsTracker::BoundInserter* inserter) {
-          inserter->AddArg(context_->storage->InternString("Details"),
-                           Variadic::String(queue_lost_message_id_));
-        };
-        const auto opt_slice_id = context_->slice_tracker->EndFrameEvent(
-            timestamp, dequeueTime->second, args_callback);
-        slice_name.reset();
-        slice_name.AppendUnsignedInt(frame_number);
-        if (opt_slice_id) {
-          auto* graphics_frame_slice_table =
-              context_->storage->mutable_graphics_frame_slice_table();
-          // Set the name of the slice to be the frame number since dequeue did
-          // not have a frame number at that time.
-          uint32_t row_idx =
-              *graphics_frame_slice_table->id().IndexOf(*opt_slice_id);
-          StringId frame_name_id =
-              context_->storage->InternString(slice_name.GetStringView());
-          graphics_frame_slice_table->mutable_name()->Set(row_idx,
-                                                          frame_name_id);
-          graphics_frame_slice_table->mutable_frame_number()->Set(row_idx,
-                                                                  frame_number);
-          dequeue_map_.erase(dequeueTime);
-        }
+      auto dequeue_time = dequeue_map_.find(buffer_id);
+      if (dequeue_time != dequeue_map_.end()) {
+        InvalidatePhaseEvent(timestamp, dequeue_time->second, true);
+        dequeue_map_.erase(dequeue_time);
       }
       track_name.reset();
       track_name.AppendLiteral("SF_");
@@ -298,15 +315,15 @@
     }
 
     case GraphicsFrameEvent::PRESENT_FENCE: {
-      auto latchTime = latch_map_.find(buffer_id);
-      if (latchTime != latch_map_.end()) {
-        context_->slice_tracker->EndFrameEvent(timestamp, latchTime->second);
-        latch_map_.erase(latchTime);
+      auto latch_time = latch_map_.find(buffer_id);
+      if (latch_time != latch_map_.end()) {
+        context_->slice_tracker->EndFrameEvent(timestamp, latch_time->second);
+        latch_map_.erase(latch_time);
       }
-      auto displayTime = display_map_.find(layer_name_id);
-      if (displayTime != display_map_.end()) {
-        context_->slice_tracker->EndFrameEvent(timestamp, displayTime->second);
-        display_map_.erase(displayTime);
+      auto display_time = display_map_.find(layer_name_id);
+      if (display_time != display_map_.end()) {
+        context_->slice_tracker->EndFrameEvent(timestamp, display_time->second);
+        display_map_.erase(display_time);
       }
       base::StringView layerName(event.layer_name());
       track_name.reset();
diff --git a/src/trace_processor/importers/proto/graphics_frame_event_parser.h b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
index e23fa73..b375c6c 100644
--- a/src/trace_processor/importers/proto/graphics_frame_event_parser.h
+++ b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
@@ -49,6 +49,10 @@
   using GraphicsFrameEvent = protos::pbzero::GraphicsFrameEvent;
   bool CreateBufferEvent(int64_t timestamp, GraphicsFrameEventDecoder& event);
   void CreatePhaseEvent(int64_t timestamp, GraphicsFrameEventDecoder& event);
+  // Invalidate a phase slice that has one of the events missing
+  void InvalidatePhaseEvent(int64_t timestamp,
+                            TrackId track_id,
+                            bool reset_name = false);
 
   TraceProcessorContext* const context_;
   const StringId graphics_event_scope_id_;
diff --git a/test/trace_processor/graphics/graphics_frame_events.out b/test/trace_processor/graphics/graphics_frame_events.out
index 8aca540..59dce99 100644
--- a/test/trace_processor/graphics/graphics_frame_events.out
+++ b/test/trace_processor/graphics/graphics_frame_events.out
@@ -19,3 +19,24 @@
 16,"Display_layer2",-1,"12",12,"layer2"
 24,"Buffer: 1",0,"PresentFenceSignaled",13,"layer1"
 24,"Display_layer1",-1,"13",13,"layer1"
+31,"Buffer: 1",0,"Dequeue",21,"layer1"
+31,"APP_1",3,"21",21,"layer1"
+34,"Buffer: 1",0,"Queue",21,"layer1"
+34,"GPU_1",-1,"21",21,"layer1"
+37,"Buffer: 1",0,"Dequeue",22,"layer1"
+37,"APP_1",4,"22",22,"layer1"
+41,"Buffer: 1",0,"Queue",22,"layer1"
+41,"GPU_1",5,"22",22,"layer1"
+46,"Buffer: 1",0,"AcquireFenceSignaled",22,"layer1"
+53,"Buffer: 2",0,"Dequeue",24,"layer2"
+53,"APP_2",-1,"0",0,"layer2"
+59,"Buffer: 2",0,"AcquireFenceSignaled",24,"layer2"
+61,"Buffer: 2",0,"Latch",24,"layer2"
+61,"SF_2",-1,"24",24,"layer2"
+63,"Buffer: 1",0,"Dequeue",25,"layer1"
+63,"APP_1",-1,"0",0,"layer1"
+73,"Buffer: 1",0,"Dequeue",26,"layer1"
+73,"APP_1",2,"26",26,"layer1"
+75,"Buffer: 1",0,"Queue",26,"layer1"
+75,"GPU_1",4,"26",26,"layer1"
+79,"Buffer: 1",0,"AcquireFenceSignaled",26,"layer1"
diff --git a/test/trace_processor/graphics/graphics_frame_events.py b/test/trace_processor/graphics/graphics_frame_events.py
index 2366ad2..bf28f1f 100755
--- a/test/trace_processor/graphics/graphics_frame_events.py
+++ b/test/trace_processor/graphics/graphics_frame_events.py
@@ -52,4 +52,19 @@
 trace.add_buffer_event_packet(ts=6, buffer_id=-1, layer_name="layer6", frame_number=14, event_type=BufferEvent.HWC_COMPOSITION_QUEUED, duration=0)
 # Missing type.
 trace.add_buffer_event_packet(ts=7, buffer_id=7, layer_name="layer7", frame_number=15, event_type=-1, duration=0)
+# Missing Acquire
+trace.add_buffer_event_packet(ts=31, buffer_id=1, layer_name="layer1", frame_number=21, event_type=BufferEvent.DEQUEUE, duration=0)
+trace.add_buffer_event_packet(ts=34, buffer_id=1, layer_name="layer1", frame_number=21, event_type=BufferEvent.QUEUE, duration=0)
+trace.add_buffer_event_packet(ts=37, buffer_id=1, layer_name="layer1", frame_number=22, event_type=BufferEvent.DEQUEUE, duration=0)
+trace.add_buffer_event_packet(ts=41, buffer_id=1, layer_name="layer1", frame_number=22, event_type=BufferEvent.QUEUE, duration=0)
+trace.add_buffer_event_packet(ts=46, buffer_id=1, layer_name="layer1", frame_number=22, event_type=BufferEvent.ACQUIRE_FENCE, duration=0)
+# Missing queue with acquire
+trace.add_buffer_event_packet(ts=53, buffer_id=2, layer_name="layer2", frame_number=24, event_type=BufferEvent.DEQUEUE, duration=0)
+trace.add_buffer_event_packet(ts=59, buffer_id=2, layer_name="layer2", frame_number=24, event_type=BufferEvent.ACQUIRE_FENCE, duration=0)
+trace.add_buffer_event_packet(ts=61, buffer_id=2, layer_name="layer2", frame_number=24, event_type=BufferEvent.LATCH, duration=0)
+# Missing queue without acquire
+trace.add_buffer_event_packet(ts=63, buffer_id=1, layer_name="layer1", frame_number=25, event_type=BufferEvent.DEQUEUE, duration=0)
+trace.add_buffer_event_packet(ts=73, buffer_id=1, layer_name="layer1", frame_number=26, event_type=BufferEvent.DEQUEUE, duration=0)
+trace.add_buffer_event_packet(ts=75, buffer_id=1, layer_name="layer1", frame_number=26, event_type=BufferEvent.QUEUE, duration=0)
+trace.add_buffer_event_packet(ts=79, buffer_id=1, layer_name="layer1", frame_number=26, event_type=BufferEvent.ACQUIRE_FENCE, duration=0)
 sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index 6f9a095..7a590ef 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -479,7 +479,8 @@
     this.selectNote(state, {id});
   },
 
-  markArea(state: StateDraft, args: {color: string, persistent: boolean}):
+  markCurrentArea(
+      state: StateDraft, args: {color: string, persistent: boolean}):
       void {
         if (state.currentSelection === null ||
             state.currentSelection.kind !== 'AREA') {
@@ -497,17 +498,36 @@
         state.currentSelection.noteId = id;
       },
 
-  toggleMarkArea(state: StateDraft, args: {persistent: boolean}) {
+  toggleMarkCurrentArea(state: StateDraft, args: {persistent: boolean}) {
     const selection = state.currentSelection;
     if (selection != null && selection.kind === 'AREA' &&
         selection.noteId !== undefined) {
       this.removeNote(state, {id: selection.noteId});
     } else {
       const color = randomColor();
-      this.markArea(state, {color, persistent: args.persistent});
+      this.markCurrentArea(state, {color, persistent: args.persistent});
     }
   },
 
+  markArea(state: StateDraft, args: {area: Area, persistent: boolean}): void {
+    const areaId = `${state.nextAreaId++}`;
+    state.areas[areaId] = {
+      id: areaId,
+      startSec: args.area.startSec,
+      endSec: args.area.endSec,
+      tracks: args.area.tracks
+    };
+    const id = args.persistent ? `${state.nextNoteId++}` : '0';
+    const color = args.persistent ? randomColor() : '#344596';
+    state.notes[id] = {
+      noteType: 'AREA',
+      id,
+      areaId,
+      color,
+      text: '',
+    };
+  },
+
   toggleVideo(state: StateDraft, _: {}): void {
     state.videoEnabled = !state.videoEnabled;
     if (!state.videoEnabled) {
@@ -601,11 +621,6 @@
       ts: args.ts,
       type: args.type,
     };
-  },
-
-  showHeapProfileFlamegraph(
-      state: StateDraft,
-      args: {id: number, upid: number, ts: number, type: string}): void {
     state.currentHeapProfileFlamegraph = {
       kind: 'HEAP_PROFILE_FLAMEGRAPH',
       id: args.id,
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index cc8a5a1..6c2fc02 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -308,9 +308,26 @@
     await this.listThreads();
     await this.loadTimelineOverview(traceTime);
     globals.dispatch(Actions.sortThreadTracks({}));
+    await this.selectFirstHeapProfile();
+
     return engineMode;
   }
 
+  private async selectFirstHeapProfile() {
+    const query = `select * from
+    (select distinct(ts) as ts, 'native' as type,
+        upid from heap_profile_allocation
+        union
+        select distinct(graph_sample_ts) as ts, 'graph' as type, upid from
+        heap_graph_object) order by ts limit 1`;
+    const profile = await assertExists(this.engine).query(query);
+    if (profile.numRecords !== 1) return;
+    const ts = profile.columns[0].longValues![0];
+    const type = profile.columns[1].stringValues![0];
+    const upid = profile.columns[2].longValues![0];
+    globals.dispatch(Actions.selectHeapProfile({id: 0, upid, ts, type}));
+  }
+
   private async listTracks() {
     this.updateStatus('Loading tracks');
     const engine = assertExists<Engine>(this.engine);
diff --git a/ui/src/frontend/keyboard_event_handler.ts b/ui/src/frontend/keyboard_event_handler.ts
index c3bb829..064994d 100644
--- a/ui/src/frontend/keyboard_event_handler.ts
+++ b/ui/src/frontend/keyboard_event_handler.ts
@@ -33,7 +33,7 @@
   const selection = globals.state.currentSelection;
   if (down && 'm' === key) {
     if (selection && selection.kind === 'AREA') {
-      globals.dispatch(Actions.toggleMarkArea({persistent: e.shiftKey}));
+      globals.dispatch(Actions.toggleMarkCurrentArea({persistent: e.shiftKey}));
     } else if (selection) {
       lockSliceSpan(e.shiftKey);
     }
@@ -198,8 +198,7 @@
         [globals.state.currentSelection.trackId] :
         [];
     const area: Area = {startSec: range.startTs, endSec: range.endTs, tracks};
-    globals.makeSelection(Actions.selectArea({area}));
-    globals.dispatch(Actions.toggleMarkArea({persistent}));
+    globals.dispatch(Actions.markArea({area, persistent}));
   }
 }
 
diff --git a/ui/src/tracks/heap_profile/frontend.ts b/ui/src/tracks/heap_profile/frontend.ts
index 8852b35..c9c7466 100644
--- a/ui/src/tracks/heap_profile/frontend.ts
+++ b/ui/src/tracks/heap_profile/frontend.ts
@@ -118,8 +118,6 @@
     if (index !== -1) {
       const ts = data.tsStarts[index];
       const type = data.types[index];
-      globals.dispatch(Actions.showHeapProfileFlamegraph(
-          {id: index, upid: this.config.upid, ts, type}));
       globals.makeSelection(Actions.selectHeapProfile(
           {id: index, upid: this.config.upid, ts, type}));
       return true;