tp: fix kernel idle tasks for boot-time traces

In boot-time traces, CPU scheduling tracks contain "swapper/0" tasks,
which should be hidden on the UI. These idle tasks show up because
kernel startup traces contain the following events:

event {
  timestamp: 17000000
  pid: 1
  task_newtask {
    pid: 0
    comm: "swapper/0"
    clone_flags: 256
    oom_score_adj: 0
  }
}

that /sbin/init creates more swapper/0 kernel idle tasks with pid/tid ==
0. Filter these task_newtask events since they do not create real new
threads.

Bug: 379009092
Change-Id: I556e085e35ca622fcfee7a3b5122f853eead05ea
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index d9b130e..59b2446 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -2268,6 +2268,22 @@
   // family) and thread creation (clone(CLONE_THREAD, ...)).
   static const uint32_t kCloneThread = 0x00010000;  // From kernel's sched.h.
 
+  if (PERFETTO_UNLIKELY(new_tid == 0)) {
+    // In the case of boot-time tracing (kernel is started with tracing
+    // enabled), the ftrace buffer will see /bin/init creating swapper/0 tasks:
+    // event {
+    //  pid: 1
+    //  task_newtask {
+    //    pid: 0
+    //    comm: "swapper/0"
+    //  }
+    // }
+    // Skip these task_newtask events since they are kernel idle tasks.
+    PERFETTO_DCHECK(source_tid == 1);
+    PERFETTO_DCHECK(base::StartsWith(evt.comm().ToStdString(), "swapper"));
+    return;
+  }
+
   // If the process is a fork, start a new process.
   if ((clone_flags & kCloneThread) == 0) {
     // This is a plain-old fork() or equivalent.
diff --git a/test/trace_processor/diff_tests/parser/parsing/tests.py b/test/trace_processor/diff_tests/parser/parsing/tests.py
index 54707c1..8af739d 100644
--- a/test/trace_processor/diff_tests/parser/parsing/tests.py
+++ b/test/trace_processor/diff_tests/parser/parsing/tests.py
@@ -1570,3 +1570,76 @@
         5230422153284,0,1306,"[NULL]"
         5230425693562,0,10,1
         """))
+
+  # Kernel idle tasks created by /sbin/init should be filtered.
+  def test_task_newtask_swapper_by_init(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          first_packet_on_sequence: true
+          ftrace_events {
+            cpu: 1
+            event {
+              timestamp: 1000000
+              pid: 0
+              task_newtask {
+                pid: 1
+                comm: "swapper/0"
+                clone_flags: 8389376
+                oom_score_adj: 0
+              }
+            }
+            event {
+              timestamp: 1000000
+              pid: 0
+              task_newtask {
+                pid: 2
+                comm: "swapper/0"
+                clone_flags: 8390400
+                oom_score_adj: 0
+              }
+            }
+            event {
+              timestamp: 17000000
+              pid: 1
+              task_newtask {
+                pid: 0
+                comm: "swapper/0"
+                clone_flags: 256
+                oom_score_adj: 0
+              }
+            }
+            event {
+              timestamp: 17000000
+              pid: 1
+              task_newtask {
+                pid: 0
+                comm: "swapper/0"
+                clone_flags: 256
+                oom_score_adj: 0
+              }
+            }
+            event {
+              timestamp: 17000000
+              pid: 1
+              task_newtask {
+                pid: 0
+                comm: "swapper/0"
+                clone_flags: 256
+                oom_score_adj: 0
+              }
+            }
+          }
+          trusted_uid: 9999
+          trusted_packet_sequence_id: 2
+          trusted_pid: 521
+          previous_packet_dropped: true
+        }
+        """),
+        query="""
+        SELECT utid, tid, name from thread where tid = 0
+        """,
+        out=Csv("""
+        "utid","tid","name"
+        0,0,"swapper"
+        """))