Handle latency CUJ state (as cancelled or timeout) (#5376)

in the stdlib all latency CUJs were considered as completed sucessfully,
even if some were not. This fixes it taking into account also the
optional instant event.

Bug: 498209719
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/cujs/sysui_cujs.sql b/src/trace_processor/perfetto_sql/stdlib/android/cujs/sysui_cujs.sql
index 015b22d..3711b29 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/cujs/sysui_cujs.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/cujs/sysui_cujs.sql
@@ -142,6 +142,34 @@
 ORDER BY
   ts ASC;
 
+-- Track IDs for all tracks named after Latency CUJs.
+CREATE PERFETTO TABLE _latency_cuj_tracks AS
+SELECT
+  id,
+  name
+FROM track
+WHERE
+  name GLOB 'L<*>';
+
+-- Markers (cancel, timeout) related to Latency CUJ slices.
+CREATE PERFETTO TABLE _latency_cuj_markers AS
+SELECT
+  cuj_slice.id AS cuj_slice_id,
+  CASE WHEN s.name = 'cancel' THEN 'cancel' ELSE 'timeout' END AS marker_type
+FROM slice AS cuj_slice
+JOIN _latency_cuj_tracks AS t
+  ON t.name = cuj_slice.name
+JOIN slice AS s
+  ON s.track_id = t.id
+WHERE
+  s.dur = 0
+  AND s.ts >= cuj_slice.ts
+  AND s.ts <= cuj_slice.ts + cuj_slice.dur
+  AND cuj_slice.name GLOB 'L<*>'
+  AND (
+    s.name = 'cancel' OR s.name = 'timeout'
+  );
+
 -- Table tracking all latency CUJs information.
 CREATE PERFETTO TABLE android_sysui_latency_cujs (
   -- Unique incremental ID for each CUJ.
@@ -179,16 +207,32 @@
   ts,
   ts + dur AS ts_end,
   dur,
-  'completed' AS state
+  CASE
+    WHEN EXISTS(
+      SELECT
+        1
+      FROM _latency_cuj_markers AS m
+      WHERE
+        m.cuj_slice_id = slice.id AND m.marker_type = 'cancel'
+    )
+    THEN 'canceled'
+    WHEN EXISTS(
+      SELECT
+        1
+      FROM _latency_cuj_markers AS m
+      WHERE
+        m.cuj_slice_id = slice.id AND m.marker_type = 'timeout'
+    )
+    THEN 'timeout'
+    ELSE 'completed'
+  END AS state
 FROM slice
 JOIN process_track
   ON slice.track_id = process_track.id
 JOIN process
   USING (upid)
 WHERE
-  -- TODO(b/447577048): Add filtering support for completed/canceled latency CUJs.
-  slice.name GLOB 'L<*>'
-  AND dur > 0;
+  slice.name GLOB 'L<*>' AND dur > 0;
 
 -- Table tracking all jank/latency CUJs information.
 CREATE PERFETTO TABLE android_jank_latency_cujs (
diff --git a/test/trace_processor/diff_tests/stdlib/android/latency_cujs_state_trace.py b/test/trace_processor/diff_tests/stdlib/android/latency_cujs_state_trace.py
new file mode 100644
index 0000000..41f7ed7
--- /dev/null
+++ b/test/trace_processor/diff_tests/stdlib/android/latency_cujs_state_trace.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# 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.
+
+import synth_common
+import sys
+
+SYSUI_PID = 5000
+SYSUI_UI_TID = 5020
+
+
+def setup_trace():
+  trace = synth_common.create_trace()
+  trace.add_packet()
+  trace.add_package_list(
+      ts=0, name="com.android.systemui", uid=10001, version_code=1)
+  trace.add_process(
+      pid=SYSUI_PID, ppid=SYSUI_PID, cmdline="com.android.systemui", uid=10001)
+  trace.add_thread(
+      tid=SYSUI_PID, tgid=SYSUI_PID, cmdline="MainThread", name="MainThread")
+  trace.add_ftrace_packet(cpu=0)
+  return trace
+
+
+trace = setup_trace()
+
+# CUJ 1: Completed
+trace.add_async_atrace_for_thread(
+    ts=10_000_000,
+    ts_end=20_000_000,
+    buf="L<CUJ_COMPLETED>",
+    pid=SYSUI_PID,
+    tid=SYSUI_UI_TID)
+
+# CUJ 2: Canceled
+trace.add_async_atrace_for_thread(
+    ts=30_000_000,
+    ts_end=40_000_000,
+    buf="L<CUJ_CANCELED>",
+    pid=SYSUI_PID,
+    tid=SYSUI_UI_TID)
+trace.add_atrace_instant_for_track(
+    ts=35_000_000,
+    buf="cancel",
+    pid=SYSUI_PID,
+    tid=SYSUI_UI_TID,
+    track_name="L<CUJ_CANCELED>")
+
+# CUJ 3: Timeout
+trace.add_async_atrace_for_thread(
+    ts=50_000_000,
+    ts_end=60_000_000,
+    buf="L<CUJ_TIMEOUT>",
+    pid=SYSUI_PID,
+    tid=SYSUI_UI_TID)
+trace.add_atrace_instant_for_track(
+    ts=55_000_000,
+    buf="timeout",
+    pid=SYSUI_PID,
+    tid=SYSUI_UI_TID,
+    track_name="L<CUJ_TIMEOUT>")
+
+sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/test/trace_processor/diff_tests/stdlib/android/sysui_cujs_test.py b/test/trace_processor/diff_tests/stdlib/android/sysui_cujs_test.py
index 7b681e1..8df5af8 100644
--- a/test/trace_processor/diff_tests/stdlib/android/sysui_cujs_test.py
+++ b/test/trace_processor/diff_tests/stdlib/android/sysui_cujs_test.py
@@ -53,3 +53,19 @@
         1,1,"com.android.systemui","L<IGNORED_CUJ_1>","IGNORED_CUJ_1",53,150000000,155000000,5000000,"completed"
         2,1,"com.android.systemui","L<IGNORED_CUJ_2>","IGNORED_CUJ_2",58,156000000,160000000,4000000,"completed"
         """))
+
+  def test_android_sysui_latency_cujs_state(self):
+    return DiffTestBlueprint(
+        trace=Path('latency_cujs_state_trace.py'),
+        query="""
+        INCLUDE PERFETTO MODULE android.cujs.sysui_cujs;
+        SELECT cuj_name, state
+        FROM android_sysui_latency_cujs
+        ORDER BY cuj_name;
+        """,
+        out=Csv("""
+        "cuj_name","state"
+        "CUJ_CANCELED","canceled"
+        "CUJ_COMPLETED","completed"
+        "CUJ_TIMEOUT","timeout"
+        """))