Merge "Add out/in thread+process info to flow events"
diff --git a/Android.bp b/Android.bp
index fc9f86f..3c5e89b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8398,6 +8398,7 @@
         "src/trace_processor/metrics/sql/android/startup/launches.sql",
         "src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql",
         "src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql",
+        "src/trace_processor/metrics/sql/android/startup/launches_minsdk33.sql",
         "src/trace_processor/metrics/sql/android/thread_counter_span_view.sql",
         "src/trace_processor/metrics/sql/android/unsymbolized_frames.sql",
         "src/trace_processor/metrics/sql/chrome/actual_power_by_category.sql",
diff --git a/BUILD b/BUILD
index 5d93094..43e1649 100644
--- a/BUILD
+++ b/BUILD
@@ -1109,6 +1109,7 @@
         "src/trace_processor/metrics/sql/android/startup/launches.sql",
         "src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql",
         "src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql",
+        "src/trace_processor/metrics/sql/android/startup/launches_minsdk33.sql",
         "src/trace_processor/metrics/sql/android/thread_counter_span_view.sql",
         "src/trace_processor/metrics/sql/android/unsymbolized_frames.sql",
         "src/trace_processor/metrics/sql/chrome/actual_power_by_category.sql",
@@ -1353,6 +1354,8 @@
         ":include_perfetto_ext_base_base",
         ":include_perfetto_ext_trace_processor_demangle",
     ],
+    deps = [
+    ] + PERFETTO_CONFIG.deps.llvm_demangle,
     linkstatic = True,
 )
 
diff --git a/CHANGELOG b/CHANGELOG
index 955527a..382f468 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,9 @@
       message.
   Trace Processor:
     * Added prebuilts for mac-arm64.
+    * Changed LIKE comparisions to be case-insenstive. This reverts the change
+      introduced in v22. GLOB should be used where case senstive searches are
+      desired; built-in metrics continue to require the use of GLOB.
     * Added an optional dependency from trace processor onto a subset of
       sources from llvm-project for function name demangling. Bazel embedders
       might need to update their PERFETTO_CONFIG in perfetto_cfg.bzl to opt in
diff --git a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
index 53c423e..e0958d4 100644
--- a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
@@ -44,7 +44,7 @@
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_HEAPPROFD() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_STDERR_CRASH_DUMP() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_X64_CPU_OPT() (0)
-#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_LLVM_DEMANGLE() (0)
+#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_LLVM_DEMANGLE() (1)
 
 // clang-format on
 #endif  // GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/protos/third_party/chromium/chrome_track_event.proto b/protos/third_party/chromium/chrome_track_event.proto
index c30f4cd..debe2a7 100644
--- a/protos/third_party/chromium/chrome_track_event.proto
+++ b/protos/third_party/chromium/chrome_track_event.proto
@@ -581,6 +581,7 @@
     NO_RESPONSE_HEAD = 52;
     ACTIVATION_NAVIGATION_DISALLOWED_FOR_BUG_1234857 = 53;
     ERROR_DOCUMENT = 54;
+    FENCED_FRAMES_EMBEDDER = 55;
   }
 
   optional BackForwardCacheNotRestoredReason
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index f83aede..862f21d 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -2020,7 +2020,8 @@
                                       protozero::ConstBytes blob) {
   protos::pbzero::UfshcdCommandFtraceEvent::Decoder evt(blob.data, blob.size);
   uint32_t num = evt.doorbell() > 0 ?
-      static_cast<uint32_t>(PERFETTO_POPCOUNT(evt.doorbell())) : 1;
+      static_cast<uint32_t>(PERFETTO_POPCOUNT(evt.doorbell())) :
+      (evt.str_t() == 1 ? 0 : 1);
 
   TrackId track = context_->track_tracker->InternGlobalCounterTrack(
       ufs_command_count_id_);
diff --git a/src/trace_processor/metrics/sql/BUILD.gn b/src/trace_processor/metrics/sql/BUILD.gn
index 5c07ca1..0ec76e6 100644
--- a/src/trace_processor/metrics/sql/BUILD.gn
+++ b/src/trace_processor/metrics/sql/BUILD.gn
@@ -79,6 +79,7 @@
   "android/unsymbolized_frames.sql",
   "android/startup/launches_maxsdk28.sql",
   "android/startup/launches_minsdk29.sql",
+  "android/startup/launches_minsdk33.sql",
   "android/startup/launches.sql",
   "android/startup/hsc.sql",
   "chrome/actual_power_by_category.sql",
diff --git a/src/trace_processor/metrics/sql/android/startup/launches.sql b/src/trace_processor/metrics/sql/android/startup/launches.sql
index 999ba6e..60c1cab 100644
--- a/src/trace_processor/metrics/sql/android/startup/launches.sql
+++ b/src/trace_processor/metrics/sql/android/startup/launches.sql
@@ -30,25 +30,31 @@
 AND (process.name IS NULL OR process.name = 'system_server');
 
 SELECT CREATE_FUNCTION(
-  'ANDROID_SDK_LEVEL()',
-  'INT', "
-    SELECT int_value
-    FROM metadata
-    WHERE name = 'android_sdk_version'
-  ");
-
-SELECT CREATE_FUNCTION(
-  'METRICS_LOGGER_SLICE_COUNT()',
+  'SLICE_COUNT(slice_glob STRING)',
   'INT',
-  "SELECT COUNT(1) FROM slice WHERE name GLOB 'MetricsLogger:*'"
+  'SELECT COUNT(1) FROM slice WHERE name GLOB $slice_glob'
+);
+
+-- All activity launches in the trace, keyed by ID.
+-- Populated by different scripts depending on the platform version / contents.
+-- See android/startup/launches*.sql
+DROP TABLE IF EXISTS launches;
+CREATE TABLE launches(
+  id INTEGER PRIMARY KEY,
+  ts BIG INT,
+  ts_end BIG INT,
+  dur BIG INT,
+  package STRING
 );
 
 -- Note: on Q, we didn't have Android fingerprints but we *did*
 -- have ActivityMetricsLogger events so we will use this approach
 -- if we see any such events.
 SELECT CASE
-  WHEN (ANDROID_SDK_LEVEL() >= 29 OR METRICS_LOGGER_SLICE_COUNT() > 0)
-  THEN RUN_METRIC('android/startup/launches_minsdk29.sql')
+  WHEN SLICE_COUNT('launchingActivity#*:*') > 0
+    THEN RUN_METRIC('android/startup/launches_minsdk33.sql')
+  WHEN SLICE_COUNT('MetricsLogger:*') > 0
+    THEN RUN_METRIC('android/startup/launches_minsdk29.sql')
   ELSE RUN_METRIC('android/startup/launches_maxsdk28.sql')
 END;
 
diff --git a/src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql b/src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql
index 8753da1..35c797e 100644
--- a/src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql
+++ b/src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql
@@ -14,23 +14,15 @@
 -- limitations under the License.
 --
 
--- All activity launches in the trace, keyed by ID.
-DROP TABLE IF EXISTS launches;
-CREATE TABLE launches(
-  id INTEGER PRIMARY KEY,
-  ts BIG INT,
-  ts_end BIG INT,
-  dur BIG INT,
-  package STRING
-);
-
 -- Cold/warm starts emitted launching slices on API level 28-.
-INSERT INTO launches(ts, ts_end, dur, package)
+INSERT INTO launches(id, ts, ts_end, dur, package)
 SELECT
+  ROW_NUMBER() OVER(ORDER BY ts) AS id,
   launching_events.ts AS ts,
   launching_events.ts_end AS ts_end,
   launching_events.ts_end - launching_events.ts AS dur,
   package_name AS package
-FROM launching_events;
+FROM launching_events
+ORDER BY ts;
 
 -- TODO(lalitm): add handling of hot starts using frame timings.
diff --git a/src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql b/src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql
index 1f4c0f7..e5631bf 100644
--- a/src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql
+++ b/src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql
@@ -53,23 +53,14 @@
 SELECT ts FROM slice
 WHERE name = 'MetricsLogger:launchObserverNotifyActivityLaunchFinished';
 
--- All activity launches in the trace, keyed by ID.
-DROP TABLE IF EXISTS launches;
-CREATE TABLE launches(
-  ts BIG INT,
-  ts_end BIG INT,
-  dur BIG INT,
-  id INT,
-  package STRING);
-
 -- Use the starting event package name. The finish event package name
 -- is not reliable in the case of failed launches.
-INSERT INTO launches
+INSERT INTO launches(id, ts, ts_end, dur, package)
 SELECT
+  lpart.id AS id,
   lpart.ts AS ts,
   launching_events.ts_end AS ts_end,
   launching_events.ts_end - lpart.ts AS dur,
-  lpart.id AS id,
   package_name AS package
 FROM launch_partitions AS lpart
 JOIN launching_events ON
diff --git a/src/trace_processor/metrics/sql/android/startup/launches_minsdk33.sql b/src/trace_processor/metrics/sql/android/startup/launches_minsdk33.sql
new file mode 100644
index 0000000..f3773bb
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/startup/launches_minsdk33.sql
@@ -0,0 +1,47 @@
+--
+-- Copyright 2022 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
+--
+--     https://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.
+--
+
+DROP VIEW IF EXISTS launch_async_events;
+CREATE VIEW launch_async_events AS
+SELECT
+  ts,
+  dur,
+  SUBSTR(name, 19) id
+FROM slice
+WHERE
+  name GLOB 'launchingActivity#*'
+  AND dur != 0
+  AND INSTR(name, ':') = 0;
+
+DROP VIEW IF EXISTS launch_complete_events;
+CREATE VIEW launch_complete_events AS
+SELECT
+  STR_SPLIT(completed, ':completed:', 0) id,
+  STR_SPLIT(completed, ':completed:', 1) package_name
+FROM (
+  SELECT SUBSTR(name, 19) completed
+  FROM slice
+  WHERE dur = 0 AND name GLOB 'launchingActivity#*:completed:*'
+);
+
+INSERT INTO launches(id, ts, ts_end, dur, package)
+SELECT
+  id,
+  ts,
+  ts + dur ts_end,
+  dur,
+  package_name
+FROM launch_async_events JOIN launch_complete_events USING (id);
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 9ace9ee..a1660ff 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -108,11 +108,6 @@
   if (error) {
     PERFETTO_FATAL("Error setting pragma temp_store: %s", error);
   }
-  sqlite3_exec(db, "PRAGMA case_sensitive_like = 1", 0, 0, &error);
-  if (error) {
-    PERFETTO_FATAL("Error setting pragma case_sensitive_like: %s", error);
-  }
-
   sqlite3_str_split_init(db);
 // In Android tree builds, we don't have the percentile module.
 // Just don't include it.
diff --git a/test/synth_common.py b/test/synth_common.py
index 92d8e3f..be52735 100644
--- a/test/synth_common.py
+++ b/test/synth_common.py
@@ -187,6 +187,9 @@
   def add_atrace_async_end(self, ts, tid, pid, buf):
     self.add_print(ts, tid, 'F|{}|{}|0'.format(pid, buf))
 
+  def add_atrace_instant(self, ts, tid, pid, buf):
+    self.add_print(ts, tid, 'I|{}|{}'.format(pid, buf))
+
   def add_process(self, pid, ppid, cmdline, uid=None):
     process = self.packet.process_tree.processes.add()
     process.pid = pid
diff --git a/test/trace_processor/startup/android_startup_minsdk33.out b/test/trace_processor/startup/android_startup_minsdk33.out
new file mode 100644
index 0000000..e7022b5
--- /dev/null
+++ b/test/trace_processor/startup/android_startup_minsdk33.out
@@ -0,0 +1,25 @@
+android_startup {
+  startup {
+    startup_id: 1
+    package_name: "com.google.android.calendar"
+    zygote_new_process: false
+    to_first_frame {
+      dur_ns: 100
+      main_thread_by_task_state {
+        running_dur_ns: 0
+        runnable_dur_ns: 0
+        uninterruptible_sleep_dur_ns: 0
+        interruptible_sleep_dur_ns: 0
+      }
+      other_processes_spawned_count: 0
+      dur_ms: 0.0001
+      mcycles_by_core_type {
+      }
+    }
+    activity_hosting_process_count: 0
+    event_timestamps {
+      intent_received: 110
+      first_frame: 210
+    }
+  }
+}
diff --git a/test/trace_processor/startup/android_startup_minsdk33.py b/test/trace_processor/startup/android_startup_minsdk33.py
new file mode 100644
index 0000000..dddc503
--- /dev/null
+++ b/test/trace_processor/startup/android_startup_minsdk33.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+# Copyright (C) 2018 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
+
+import synth_common
+
+trace = synth_common.create_trace()
+trace.add_packet()
+trace.add_process(1, 0, 'init')
+trace.add_process(2, 1, 'system_server')
+trace.add_process(3, 1, 'com.google.android.calendar', 10001)
+
+trace.add_package_list(
+    ts=1, name='com.google.android.calendar', uid=10001, version_code=123)
+
+trace.add_ftrace_packet(cpu=0)
+trace.add_atrace_async_begin(ts=110, tid=2, pid=2, buf='launchingActivity#1')
+trace.add_atrace_async_end(ts=210, tid=2, pid=2, buf='launchingActivity#1')
+trace.add_atrace_instant(
+    ts=211,
+    tid=2,
+    pid=2,
+    buf='launchingActivity#1:completed:com.google.android.calendar')
+
+sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/test/trace_processor/startup/index b/test/trace_processor/startup/index
index 1780fa8..ee6003e 100644
--- a/test/trace_processor/startup/index
+++ b/test/trace_processor/startup/index
@@ -2,6 +2,7 @@
 
 # Startup metric tests.
 android_startup.py android_startup android_startup.out
+android_startup_minsdk33.py android_startup android_startup_minsdk33.out
 android_startup_breakdown.py android_startup android_startup_breakdown.out
 android_startup_process_track.py android_startup android_startup_process_track.out
 android_startup_attribution.py android_startup android_startup_attribution.out
diff --git a/tools/gen_bazel b/tools/gen_bazel
index cf02e0d..76f1b6e 100755
--- a/tools/gen_bazel
+++ b/tools/gen_bazel
@@ -46,7 +46,7 @@
     'enable_perfetto_heapprofd=false',
     'enable_perfetto_traced_perf=false',
     'perfetto_force_dcheck="off"',
-    'enable_perfetto_llvm_demangle=false',
+    'enable_perfetto_llvm_demangle=true',
 ])
 
 # Default targets to translate to the blueprint file.
diff --git a/ui/src/frontend/base_slice_track.ts b/ui/src/frontend/base_slice_track.ts
index 55eed50..0b11366 100644
--- a/ui/src/frontend/base_slice_track.ts
+++ b/ui/src/frontend/base_slice_track.ts
@@ -109,6 +109,12 @@
   private computedSliceHeight = 0;
   private computedRowSpacing = 0;
 
+  // True if this track (and any views tables it might have created) has been
+  // destroyed. This is unfortunately error prone (since we must manually check
+  // this between each query).
+  // TODO(hjd): Replace once we have cancellable query sequences.
+  private isDestroyed = false;
+
   // TODO(hjd): Remove when updating selection.
   // We shouldn't know here about CHROME_SLICE. Maybe should be set by
   // whatever deals with that. Dunno the namespace of selection is weird. For
@@ -357,6 +363,12 @@
     }  // if (howSlice)
   }
 
+  onDestroy() {
+    super.onDestroy();
+    this.isDestroyed = true;
+    this.engine.query(`DROP VIEW IF EXISTS ${this.tableName}`);
+  }
+
   // This method figures out if the visible window is outside the bounds of
   // the cached data and if so issues new queries (i.e. sorta subsumes the
   // onBoundsChange).
@@ -366,16 +378,14 @@
     if (this.sqlState === 'UNINITIALIZED') {
       this.sqlState = 'INITIALIZING';
 
-      // TODO(hjd): we need an onDestroy. Right now if you contract and expand a
-      // track group this will crash, because the 2nd time we create the track
-      // we end up re-issuing the CREATE VIEW table_name.
-      // Right now this DROP VIEW is a hack, because it: (1) assumes that
-      // tableName is a VIEW and not a TABLE; (2) assume the impl track didn't
-      // create any other TABLE/VIEW (which happens to be true right now but
-      // might now be in future).
-      await this.engine.query(`DROP VIEW IF EXISTS ${this.tableName}`);
+      if (this.isDestroyed) {
+        return;
+      }
       await this.initSqlTable(this.tableName);
 
+      if (this.isDestroyed) {
+        return;
+      }
       const queryRes = await this.engine.query(`select
           ifnull(max(dur), 0) as maxDur, count(1) as rowCount
           from ${this.tableName}`);
@@ -424,6 +434,9 @@
     // - Materialize the unfinished slices one off.
     // - Avoid the union if we know we don't have any -1 slices.
     // - Maybe we don't need the union at all and can deal in TS?
+    if (this.isDestroyed) {
+      return;
+    }
     const queryRes = await this.engine.query(`
     with q1 as (
       select
diff --git a/ui/src/frontend/details_panel.ts b/ui/src/frontend/details_panel.ts
index da5298e..30f536e 100644
--- a/ui/src/frontend/details_panel.ts
+++ b/ui/src/frontend/details_panel.ts
@@ -332,9 +332,10 @@
       detailsPanels.push({
         key: 'pivot_table_redux',
         name: 'Pivot Table',
-        vnode:
-            m(PivotTableRedux,
-              {selectionArea: globals.state.pivotTableRedux.selectionArea})
+        vnode: m(PivotTableRedux, {
+          key: 'pivot_table_redux',
+          selectionArea: globals.state.pivotTableRedux.selectionArea
+        })
       });
     }
 
@@ -379,7 +380,7 @@
       detailsPanels.push({
         key: 'selected_flows',
         name: 'Flow Events',
-        vnode: m(FlowEventsAreaSelectedPanel)
+        vnode: m(FlowEventsAreaSelectedPanel, {key: 'flow_events_area'})
       });
     }
 
diff --git a/ui/src/frontend/track.ts b/ui/src/frontend/track.ts
index 5cd1e9b..0c5716a 100644
--- a/ui/src/frontend/track.ts
+++ b/ui/src/frontend/track.ts
@@ -77,6 +77,10 @@
     this.lastTrackState = assertExists(globals.state.tracks[this.trackId]);
   }
 
+  // Last call the track will receive. Called just before the last reference to
+  // this object is removed.
+  onDestroy() {}
+
   protected abstract renderCanvas(ctx: CanvasRenderingContext2D): void;
 
   protected get trackState(): TrackState {
diff --git a/ui/src/frontend/track_group_panel.ts b/ui/src/frontend/track_group_panel.ts
index e5f6631..7f0b4e9 100644
--- a/ui/src/frontend/track_group_panel.ts
+++ b/ui/src/frontend/track_group_panel.ts
@@ -172,6 +172,13 @@
     }
   }
 
+  onremove() {
+    if (this.summaryTrack !== undefined) {
+      this.summaryTrack.onDestroy();
+      this.summaryTrack = undefined;
+    }
+  }
+
   highlightIfTrackSelected(ctx: CanvasRenderingContext2D, size: PanelSize) {
     const localState = globals.frontendLocalState;
     const selection = globals.state.currentSelection;
diff --git a/ui/src/frontend/track_panel.ts b/ui/src/frontend/track_panel.ts
index a916e93..e479628 100644
--- a/ui/src/frontend/track_panel.ts
+++ b/ui/src/frontend/track_panel.ts
@@ -326,6 +326,13 @@
     }
   }
 
+  onremove() {
+    if (this.track !== undefined) {
+      this.track.onDestroy();
+      this.track = undefined;
+    }
+  }
+
   highlightIfTrackSelected(ctx: CanvasRenderingContext2D, size: PanelSize) {
     const localState = globals.frontendLocalState;
     const selection = globals.state.currentSelection;