tp: stdlib: Add DrawFrames and SurfaceFlinger lookup stages
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/input.sql b/src/trace_processor/perfetto_sql/stdlib/android/input.sql
index a27f51f..fb3590c 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/input.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/input.sql
@@ -534,8 +534,117 @@
   frame_id
 );
 
--- Retrieves the full lifecycle of an Android input event (Read -> Dispatch -> Receive -> Consume -> Frame)
+CREATE PERFETTO TABLE _draw_frames_lookup AS
+SELECT id, track_id, ts, dur, cast_int!(str_split(name, ' ', 1)) AS vsync_id
+FROM slice
+WHERE
+  name GLOB 'DrawFrames *';
+
+CREATE PERFETTO INDEX _draw_frames_lookup_idx ON _draw_frames_lookup(vsync_id);
+
+CREATE PERFETTO TABLE _input_sf_process AS
+SELECT upid FROM process WHERE name = '/system/bin/surfaceflinger' LIMIT 1;
+
+CREATE PERFETTO TABLE _input_sf_main_thread AS
+SELECT thread_track.id AS track_id
+FROM thread_track
+JOIN thread USING (utid)
+JOIN _input_sf_process USING (upid)
+WHERE
+  thread.is_main_thread;
+
+CREATE PERFETTO TABLE _surfaceflinger_composite_lookup AS
+SELECT id, track_id, ts, dur, cast_int!(str_split(name, ' ', 1)) AS vsync_id
+FROM slice
+WHERE
+  track_id IN (SELECT track_id FROM _input_sf_main_thread)
+  AND name GLOB 'composite *';
+
+CREATE PERFETTO INDEX _surfaceflinger_composite_lookup_idx ON _surfaceflinger_composite_lookup(
+  vsync_id
+);
+
+-- Retrieves the full lifecycle of an Android input event (Read -> Dispatch -> Receive -> Consume -> Frame -> DrawFrames -> SurfaceFlinger)
 -- by matching a given slice ID from any stage of the pipeline.
+CREATE PERFETTO TABLE _input_reader_notify_lookup AS
+SELECT
+  id,
+  ts,
+  dur,
+  track_id,
+  str_split(str_split(str_split(name, 'id=', 1), ',', 0), ')', 0) AS reader_input_id
+FROM slice
+WHERE
+  name GLOB 'UnwantedInteractionBlocker::notifyMotion*';
+
+CREATE PERFETTO INDEX _input_reader_notify_lookup_idx ON _input_reader_notify_lookup(
+  reader_input_id
+);
+
+CREATE PERFETTO TABLE _prepare_dispatch_cycle_lookup AS
+SELECT
+  id,
+  str_split(str_split(str_split(name, 'id=', 1), ',', 0), ')', 0) AS dispatch_id,
+  str_split(str_split(name, 'inputChannel=', 1), ', id=', 0) AS event_channel
+FROM slice
+WHERE
+  name GLOB 'prepareDispatchCycleLocked*';
+
+CREATE PERFETTO INDEX _prepare_dispatch_cycle_lookup_idx ON _prepare_dispatch_cycle_lookup(
+  dispatch_id
+);
+
+CREATE PERFETTO TABLE _send_message_lookup AS
+SELECT
+  id,
+  ts,
+  dur,
+  track_id,
+  str_split(str_split(name, '=', 2), ',', 0) AS event_seq,
+  str_split(str_split(name, '=', 1), ',', 0) AS event_channel
+FROM slice
+WHERE
+  name GLOB 'sendMessage(*type=MOTION)'
+  OR name GLOB 'sendMessage(*type=KEY)';
+
+CREATE PERFETTO INDEX _send_message_lookup_idx ON _send_message_lookup(
+  event_seq,
+  event_channel
+);
+
+CREATE PERFETTO TABLE _receive_message_lookup AS
+SELECT
+  id,
+  ts,
+  dur,
+  track_id,
+  str_split(str_split(name, '=', 2), ',', 0) AS event_seq,
+  str_split(str_split(name, '=', 1), ',', 0) AS event_channel
+FROM slice
+WHERE
+  name GLOB 'receiveMessage(*type=MOTION)'
+  OR name GLOB 'receiveMessage(*type=KEY)';
+
+CREATE PERFETTO INDEX _receive_message_lookup_idx ON _receive_message_lookup(id);
+
+CREATE PERFETTO TABLE _deliver_input_event_lookup AS
+SELECT
+  s.id,
+  s.ts,
+  s.dur,
+  s.track_id,
+  str_split(s.name, '=', 3) AS input_event_id,
+  t.upid
+FROM slice AS s
+JOIN thread_track AS tt ON s.track_id = tt.id
+JOIN thread AS t USING (utid)
+WHERE
+  s.name GLOB 'deliverInputEvent src=*';
+
+CREATE PERFETTO INDEX _deliver_input_event_lookup_idx ON _deliver_input_event_lookup(
+  input_event_id
+);
+
 CREATE PERFETTO FUNCTION _android_input_lifecycle_by_slice_id(
   -- The Slice ID any slice in the input lifecycle.
   slice_id LONG
@@ -553,6 +662,8 @@
   ts_receive LONG,
   ts_consume LONG,
   ts_frame LONG,
+  ts_draw_frames LONG,
+  ts_sf LONG,
   -- InputReader Stage
   id_reader LONG,
   track_reader LONG,
@@ -573,47 +684,207 @@
   id_frame LONG,
   track_frame LONG,
   dur_frame LONG,
+  -- DrawFrames Stage
+  id_draw_frames LONG,
+  track_draw_frames LONG,
+  dur_draw_frames LONG,
+  -- SurfaceFlinger Stage
+  id_sf LONG,
+  track_sf LONG,
+  dur_sf LONG,
   is_speculative_frame BOOL
 )
 AS
+WITH
+  resolved_input_event_id AS (
+    SELECT
+      COALESCE(
+        -- Case 1: Clicked Reader (UnwantedInteractionBlocker)
+        (
+          SELECT reader_input_id
+          FROM _input_reader_notify_lookup
+          WHERE
+            id = $slice_id
+        ),
+        -- Case 2: Clicked prepareDispatchCycleLocked
+        (
+          SELECT dispatch_id
+          FROM _prepare_dispatch_cycle_lookup
+          WHERE
+            id = $slice_id
+        ),
+        -- Case 3: Clicked deliverInputEvent itself
+        (
+          SELECT input_event_id
+          FROM _deliver_input_event_lookup
+          WHERE
+            id = $slice_id
+        )
+      ) AS input_event_id
+  ),
+  resolved_keys AS (
+    SELECT sm.event_seq, sm.event_channel
+    FROM resolved_input_event_id AS r
+    JOIN _prepare_dispatch_cycle_lookup AS prep
+      ON prep.dispatch_id = r.input_event_id
+    JOIN descendant_slice(prep.id) AS child
+    JOIN _send_message_lookup AS sm
+      ON sm.id = child.id
+    WHERE
+      r.input_event_id IS NOT NULL
+    LIMIT 1
+  ),
+  base_event AS (
+    -- Match by explicit socket key (Reader, Prepare, deliverInputEvent)
+    SELECT e.*
+    FROM android_input_events AS e
+    JOIN resolved_keys AS rk
+      ON e.event_seq = rk.event_seq
+      AND e.event_channel = rk.event_channel
+    UNION ALL
+    -- Match by explicit (seq, channel) directly (Clicked sendMessage)
+    SELECT e.*
+    FROM android_input_events AS e
+    JOIN _send_message_lookup AS sm
+      ON sm.id = $slice_id
+      AND e.event_seq = sm.event_seq
+      AND e.event_channel = sm.event_channel
+    WHERE
+      NOT EXISTS (SELECT 1 FROM resolved_keys)
+    UNION ALL
+    -- Match by explicit (seq, channel) directly (Clicked receiveMessage)
+    SELECT e.*
+    FROM android_input_events AS e
+    JOIN _receive_message_lookup AS rm
+      ON rm.id = $slice_id
+      AND e.event_seq = rm.event_seq
+      AND e.event_channel = rm.event_channel
+    WHERE
+      NOT EXISTS (SELECT 1 FROM resolved_keys)
+    UNION ALL
+    -- Match by Consumer Cookie directly (Clicked InputConsumer)
+    SELECT e.*
+    FROM android_input_events AS e
+    JOIN _input_consumers_lookup AS cons
+      ON cons.id = $slice_id
+      AND e.event_seq = cons.cookie
+    WHERE
+      NOT EXISTS (SELECT 1 FROM resolved_keys)
+    UNION ALL
+    -- Match by Choreographer Frame directly
+    SELECT e.*
+    FROM android_input_events AS e
+    JOIN _frame_choreographer_lookup AS chor
+      ON chor.id = $slice_id
+      AND e.frame_id = chor.frame_id
+    WHERE
+      NOT EXISTS (SELECT 1 FROM resolved_keys)
+    UNION ALL
+    -- Match by DrawFrames Vsync directly
+    SELECT e.*
+    FROM android_input_events AS e
+    JOIN _draw_frames_lookup AS draw
+      ON draw.id = $slice_id
+      AND e.frame_id = draw.vsync_id
+    WHERE
+      NOT EXISTS (SELECT 1 FROM resolved_keys)
+    UNION ALL
+    -- Match by SurfaceFlinger Vsync directly
+    SELECT e.*
+    FROM android_input_events AS e
+    JOIN _surfaceflinger_composite_lookup AS sf
+      ON sf.id = $slice_id
+    JOIN actual_frame_timeline_slice AS sf_timeline
+      ON sf_timeline.name = CAST(sf.vsync_id AS TEXT)
+      AND sf_timeline.upid IN (SELECT upid FROM _input_sf_process)
+    JOIN flow
+      ON flow.slice_in = sf_timeline.id
+    JOIN actual_frame_timeline_slice AS app_timeline
+      ON app_timeline.id = flow.slice_out
+    WHERE
+      e.frame_id = CAST(app_timeline.name AS LONG)
+      AND NOT EXISTS (SELECT 1 FROM resolved_keys)
+  ),
+  sf_resolved AS (
+    SELECT s.id, s.track_id, s.ts, s.dur, base.frame_id
+    FROM base_event AS base
+    JOIN actual_frame_timeline_slice AS app_timeline
+      ON app_timeline.name = CAST(base.frame_id AS TEXT)
+    JOIN flow
+      ON flow.slice_out = app_timeline.id
+    JOIN actual_frame_timeline_slice AS sf_timeline
+      ON sf_timeline.id = flow.slice_in
+    JOIN _surfaceflinger_composite_lookup AS s
+      ON s.vsync_id = CAST(sf_timeline.name AS LONG)
+    WHERE
+      sf_timeline.upid IN (SELECT upid FROM _input_sf_process)
+    LIMIT 1
+  )
 SELECT
   e.input_event_id AS input_id,
   e.event_channel AS channel,
   e.end_to_end_latency_dur AS total_latency,
-  e.read_time AS ts_reader,
-  e.dispatch_ts AS ts_dispatch,
-  e.receive_ts AS ts_receive,
-  s_cons.ts AS ts_consume,
-  s_frame.ts AS ts_frame,
-  s_read.id AS id_reader,
-  s_read.track_id AS track_reader,
-  s_read.dur AS dur_reader,
-  s_disp.id AS id_dispatch,
-  e.dispatch_track_id AS track_dispatch,
-  s_disp.dur AS dur_dispatch,
+  reader.ts AS ts_reader,
+  disp.ts AS ts_dispatch,
+  s_recv.ts AS ts_receive,
+  cons.ts AS ts_consume,
+  chor.ts AS ts_frame,
+  draw.ts AS ts_draw_frames,
+  sf.ts AS ts_sf,
+  reader.id AS id_reader,
+  reader.track_id AS track_reader,
+  reader.dur AS dur_reader,
+  disp.id AS id_dispatch,
+  disp.track_id AS track_dispatch,
+  disp.dur AS dur_dispatch,
   s_recv.id AS id_receive,
   e.receive_track_id AS track_receive,
   s_recv.dur AS dur_receive,
-  s_cons.id AS id_consume,
-  s_cons.track_id AS track_consume,
-  s_cons.dur AS dur_consume,
-  s_frame.id AS id_frame,
-  s_frame.track_id AS track_frame,
-  s_frame.dur AS dur_frame,
+  cons.id AS id_consume,
+  cons.track_id AS track_consume,
+  cons.dur AS dur_consume,
+  chor.id AS id_frame,
+  chor.track_id AS track_frame,
+  chor.dur AS dur_frame,
+  draw.id AS id_draw_frames,
+  draw.track_id AS track_draw_frames,
+  draw.dur AS dur_draw_frames,
+  sf.id AS id_sf,
+  sf.track_id AS track_sf,
+  sf.dur AS dur_sf,
   e.is_speculative_frame
-FROM android_input_events AS e
-LEFT JOIN slice AS s_read
-  ON s_read.ts = e.read_time
-  AND s_read.track_id != 0
-LEFT JOIN slice AS s_disp
-  ON s_disp.ts = e.dispatch_ts
-  AND s_disp.track_id = e.dispatch_track_id
+FROM base_event AS e
+LEFT JOIN _input_reader_notify_lookup AS reader
+  ON reader.ts = e.read_time
+LEFT JOIN _send_message_lookup AS disp
+  ON disp.ts = e.dispatch_ts
+  AND disp.track_id = e.dispatch_track_id
 LEFT JOIN slice AS s_recv
   ON s_recv.ts = e.receive_ts
   AND s_recv.track_id = e.receive_track_id
-LEFT JOIN _input_consumers_lookup AS s_cons
-  ON s_cons.cookie = e.event_seq
-LEFT JOIN _frame_choreographer_lookup AS s_frame
-  ON s_frame.frame_id = CAST(e.frame_id AS LONG)
+LEFT JOIN _input_consumers_lookup AS cons
+  ON cons.cookie = e.event_seq
+LEFT JOIN _frame_choreographer_lookup AS chor
+  ON chor.frame_id = CAST(e.frame_id AS LONG)
+LEFT JOIN _draw_frames_lookup AS draw
+  ON draw.vsync_id = CAST(e.frame_id AS LONG)
+LEFT JOIN sf_resolved AS sf
+  ON sf.frame_id = e.frame_id
+LEFT JOIN _prepare_dispatch_cycle_lookup AS prep
+  ON prep.dispatch_id = e.input_event_id
+  AND prep.event_channel = e.event_channel
+LEFT JOIN _deliver_input_event_lookup AS del
+  ON del.input_event_id = e.input_event_id
+  AND del.upid = e.upid
 WHERE
-  $slice_id IN (s_read.id, s_disp.id, s_recv.id, s_cons.id, s_frame.id);
+  $slice_id IN (
+    reader.id,
+    disp.id,
+    s_recv.id,
+    cons.id,
+    chor.id,
+    draw.id,
+    sf.id,
+    prep.id,
+    del.id
+  );