tp: TrackEvent extension plugin + android_track_event_process table

TrackEventParser exposes a field-id-keyed plugin registry. Empty
registry costs one bool check per packet; minimal trace_processor
links no extension protos.

The frameworks/base plugin records AndroidProcessStartEvent (2010)
start_ts and AndroidBinderDiedEvent (2013) end_ts into a new
__intrinsic_android_track_event_process table (upid, start_ts,
end_ts). process.start_ts/end_ts are not touched -- those remain
the ftrace view.

Drops IMPORTANCE_BACKGROUND from frameworks_base_track_event.proto:
pbzero's switch-based ToString rejects aliased enumerators under
-Werror, and BACKGROUND was an alias for CACHED (= 400).

Change-Id: I578d66d0185c10978ca0e88603aacaf1fa14931a
diff --git a/protos/third_party/android/frameworks/base/proto/tracing/frameworks_base_track_event.proto b/protos/third_party/android/frameworks/base/proto/tracing/frameworks_base_track_event.proto
index 4f4b399..8c3d066 100644
--- a/protos/third_party/android/frameworks/base/proto/tracing/frameworks_base_track_event.proto
+++ b/protos/third_party/android/frameworks/base/proto/tracing/frameworks_base_track_event.proto
@@ -277,8 +277,6 @@
 }
 
 enum Importance {
-  option allow_alias = true;
-
   IMPORTANCE_UNKNOWN = 0;
   IMPORTANCE_FOREGROUND = 100;
   IMPORTANCE_FOREGROUND_SERVICE = 125;
@@ -291,7 +289,6 @@
   IMPORTANCE_TOP_SLEEPING = 325;
   IMPORTANCE_CANT_SAVE_STATE = 350;
   IMPORTANCE_CACHED = 400;
-  IMPORTANCE_BACKGROUND = 400;
   IMPORTANCE_EMPTY = 500;
   IMPORTANCE_GONE = 1000;
 }
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index b0f9142..dfc2ee2 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -66,6 +66,8 @@
     "track_event_module.h",
     "track_event_parser.cc",
     "track_event_parser.h",
+    "track_event_plugin.cc",
+    "track_event_plugin.h",
     "track_event_sequence_state.cc",
     "track_event_tokenizer.cc",
     "track_event_tokenizer.h",
@@ -135,6 +137,8 @@
     "android_cpu_per_uid_module.h",
     "android_cpu_per_uid_state.cc",
     "android_cpu_per_uid_state.h",
+    "android_framework_track_event_parser.cc",
+    "android_framework_track_event_parser.h",
     "android_kernel_wakelocks_module.cc",
     "android_kernel_wakelocks_module.h",
     "android_kernel_wakelocks_state.cc",
@@ -225,6 +229,7 @@
     "../../../../protos/perfetto/trace/sys_stats:zero",
     "../../../../protos/perfetto/trace/system_info:zero",
     "../../../../protos/perfetto/trace/translation:zero",
+    "../../../../protos/third_party/android/frameworks/base/proto/tracing:frameworks_base_track_event_zero",
     "../../../base",
     "../../../kernel_utils:kernel_wakelock_errors",
     "../../../kernel_utils:syscall_table",
diff --git a/src/trace_processor/importers/proto/additional_modules.cc b/src/trace_processor/importers/proto/additional_modules.cc
index 6a0c537..48ce4fa 100644
--- a/src/trace_processor/importers/proto/additional_modules.cc
+++ b/src/trace_processor/importers/proto/additional_modules.cc
@@ -26,6 +26,7 @@
 #include "src/trace_processor/importers/proto/android_camera_event_module.h"
 #include "src/trace_processor/importers/proto/android_cpu_per_uid_module.h"
 #include "src/trace_processor/importers/proto/android_extension.descriptor.h"
+#include "src/trace_processor/importers/proto/android_framework_track_event_parser.h"
 #include "src/trace_processor/importers/proto/android_kernel_wakelocks_module.h"
 #include "src/trace_processor/importers/proto/android_probes_module.h"
 #include "src/trace_processor/importers/proto/app_wakelock_module.h"
@@ -41,6 +42,7 @@
 #include "src/trace_processor/importers/proto/statsd_module.h"
 #include "src/trace_processor/importers/proto/system_probes_module.h"
 #include "src/trace_processor/importers/proto/trace.descriptor.h"
+#include "src/trace_processor/importers/proto/track_event_module.h"
 #include "src/trace_processor/importers/proto/translation_table_module.h"
 #include "src/trace_processor/importers/proto/v8_module.h"
 #include "src/trace_processor/types/trace_processor_context.h"
@@ -102,6 +104,9 @@
   module_context->etw_module =
       static_cast<EtwModule*>(module_context->modules.back().get());
 
+  AndroidFrameworkTrackEventParser::Register(
+      context, module_context->track_module->parser());
+
   if (context->config.analyze_trace_proto_content) {
     context->content_analyzer = std::make_unique<ProtoContentAnalyzer>(context);
   }
diff --git a/src/trace_processor/importers/proto/android_framework_track_event_parser.cc b/src/trace_processor/importers/proto/android_framework_track_event_parser.cc
new file mode 100644
index 0000000..2542e36
--- /dev/null
+++ b/src/trace_processor/importers/proto/android_framework_track_event_parser.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2026 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.
+ */
+
+#include "src/trace_processor/importers/proto/android_framework_track_event_parser.h"
+
+#include <memory>
+
+#include "perfetto/protozero/field.h"
+#include "protos/third_party/android/frameworks/base/proto/tracing/frameworks_base_track_event.pbzero.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto::trace_processor {
+
+namespace {
+using FBTE = ::com::android::internal::pbzero::FrameworksBaseTrackEvent;
+using AndroidProcessStartEvent =
+    ::com::android::internal::pbzero::AndroidProcessStartEvent;
+using AndroidBinderDiedEvent =
+    ::com::android::internal::pbzero::AndroidBinderDiedEvent;
+}  // namespace
+
+// static
+void AndroidFrameworkTrackEventParser::Register(TraceProcessorContext* context,
+                                                TrackEventParser* parser) {
+  auto plugin = std::make_unique<AndroidFrameworkTrackEventParser>(context);
+  auto* p = plugin.get();
+  auto& registry = parser->mutable_plugins();
+  registry.RegisterFieldHandler(FBTE::kProcessStartEventFieldNumber,
+                                [p](protozero::ConstBytes data, int64_t ts) {
+                                  p->HandleProcessStart(data, ts);
+                                });
+  registry.RegisterFieldHandler(FBTE::kBinderDiedEventFieldNumber,
+                                [p](protozero::ConstBytes data, int64_t ts) {
+                                  p->HandleBinderDied(data, ts);
+                                });
+  registry.RegisterPlugin(std::move(plugin));
+}
+
+AndroidFrameworkTrackEventParser::AndroidFrameworkTrackEventParser(
+    TraceProcessorContext* context)
+    : context_(context) {}
+
+AndroidFrameworkTrackEventParser::~AndroidFrameworkTrackEventParser() = default;
+
+tables::AndroidTrackEventProcessTable::RowReference
+AndroidFrameworkTrackEventParser::RowFor(int64_t pid) {
+  UniquePid upid =
+      context_->process_tracker->GetOrCreateProcessWithoutMainThread(pid);
+  auto* table = context_->storage->mutable_android_track_event_process_table();
+  auto it_and_ins =
+      upid_to_row_.Insert(upid, tables::AndroidTrackEventProcessTable::Id{0});
+  if (it_and_ins.second) {
+    tables::AndroidTrackEventProcessTable::Row row;
+    row.upid = upid;
+    *it_and_ins.first = table->Insert(row).id;
+  }
+  return (*table)[*it_and_ins.first];
+}
+
+void AndroidFrameworkTrackEventParser::HandleProcessStart(
+    protozero::ConstBytes data,
+    int64_t ts) {
+  AndroidProcessStartEvent::Decoder evt(data);
+  if (!evt.has_pid())
+    return;
+  auto row = RowFor(evt.pid());
+  if (!row.start_ts().has_value())
+    row.set_start_ts(ts);
+}
+
+void AndroidFrameworkTrackEventParser::HandleBinderDied(
+    protozero::ConstBytes data,
+    int64_t ts) {
+  AndroidBinderDiedEvent::Decoder evt(data);
+  if (!evt.has_pid())
+    return;
+  auto row = RowFor(evt.pid());
+  if (!row.end_ts().has_value())
+    row.set_end_ts(ts);
+}
+
+}  // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/proto/android_framework_track_event_parser.h b/src/trace_processor/importers/proto/android_framework_track_event_parser.h
new file mode 100644
index 0000000..24a6142
--- /dev/null
+++ b/src/trace_processor/importers/proto/android_framework_track_event_parser.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2026 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_ANDROID_FRAMEWORK_TRACK_EVENT_PARSER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_ANDROID_FRAMEWORK_TRACK_EVENT_PARSER_H_
+
+#include <cstdint>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/protozero/field.h"
+#include "src/trace_processor/importers/proto/track_event_parser.h"
+#include "src/trace_processor/importers/proto/track_event_plugin.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/tables/android_tables_py.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto::trace_processor {
+
+// Records AndroidProcessStartEvent and AndroidBinderDiedEvent into
+// __intrinsic_android_track_event_process (upid, start_ts, end_ts).
+class AndroidFrameworkTrackEventParser
+    : public TrackEventPluginRegistry::Plugin {
+ public:
+  static void Register(TraceProcessorContext* context,
+                       TrackEventParser* parser);
+
+  explicit AndroidFrameworkTrackEventParser(TraceProcessorContext* context);
+  ~AndroidFrameworkTrackEventParser() override;
+
+ private:
+  void HandleProcessStart(protozero::ConstBytes data, int64_t ts);
+  void HandleBinderDied(protozero::ConstBytes data, int64_t ts);
+  tables::AndroidTrackEventProcessTable::RowReference RowFor(int64_t pid);
+
+  TraceProcessorContext* context_;
+  base::FlatHashMap<UniquePid, tables::AndroidTrackEventProcessTable::Id>
+      upid_to_row_;
+};
+
+}  // namespace perfetto::trace_processor
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_ANDROID_FRAMEWORK_TRACK_EVENT_PARSER_H_
diff --git a/src/trace_processor/importers/proto/track_event_event_importer.h b/src/trace_processor/importers/proto/track_event_event_importer.h
index c7cb96c..b4bdd16 100644
--- a/src/trace_processor/importers/proto/track_event_event_importer.h
+++ b/src/trace_processor/importers/proto/track_event_event_importer.h
@@ -1297,6 +1297,8 @@
         parser_->AddActiveProcess(ts_, *it);
       }
     }
+    parser_->plugins().Dispatch(blob_, ts_);
+
     if (event_.has_correlation_id()) {
       base::StackString<512> id_str("tp:#%" PRIu64, event_.correlation_id());
       inserter->AddArg(parser_->correlation_id_key_id_,
diff --git a/src/trace_processor/importers/proto/track_event_module.h b/src/trace_processor/importers/proto/track_event_module.h
index 8637950..17654c1 100644
--- a/src/trace_processor/importers/proto/track_event_module.h
+++ b/src/trace_processor/importers/proto/track_event_module.h
@@ -58,6 +58,8 @@
 
   void OnEventsFullyExtracted() override;
 
+  TrackEventParser* parser() { return &parser_; }
+
  private:
   std::unique_ptr<TrackEventTracker> track_event_tracker_;
   TrackEventTokenizer tokenizer_;
diff --git a/src/trace_processor/importers/proto/track_event_parser.h b/src/trace_processor/importers/proto/track_event_parser.h
index d7acfa8..e14f24c 100644
--- a/src/trace_processor/importers/proto/track_event_parser.h
+++ b/src/trace_processor/importers/proto/track_event_parser.h
@@ -25,6 +25,7 @@
 #include "src/trace_processor/importers/common/slice_tracker.h"
 #include "src/trace_processor/importers/proto/active_chrome_processes_tracker.h"
 #include "src/trace_processor/importers/proto/chrome_string_lookup.h"
+#include "src/trace_processor/importers/proto/track_event_plugin.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/util/proto_to_args_parser.h"
 
@@ -65,6 +66,9 @@
 
   void OnEventsFullyExtracted();
 
+  TrackEventPluginRegistry& mutable_plugins() { return plugins_; }
+  const TrackEventPluginRegistry& plugins() const { return plugins_; }
+
  private:
   friend class TrackEventEventImporter;
 
@@ -132,6 +136,8 @@
   std::vector<uint32_t> reflect_fields_;
   ActiveChromeProcessesTracker active_chrome_processes_tracker_;
   DummyMemoryMapping* inline_callstack_dummy_mapping_ = nullptr;
+
+  TrackEventPluginRegistry plugins_;
 };
 
 }  // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/proto/track_event_plugin.cc b/src/trace_processor/importers/proto/track_event_plugin.cc
new file mode 100644
index 0000000..af214ef
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_plugin.cc
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2026 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.
+ */
+
+#include "src/trace_processor/importers/proto/track_event_plugin.h"
+
+namespace perfetto::trace_processor {
+
+TrackEventPluginRegistry::Plugin::~Plugin() = default;
+
+}  // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/proto/track_event_plugin.h b/src/trace_processor/importers/proto/track_event_plugin.h
new file mode 100644
index 0000000..778a701
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_plugin.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2026 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_PLUGIN_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_PLUGIN_H_
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/protozero/field.h"
+#include "perfetto/protozero/proto_decoder.h"
+
+namespace perfetto::trace_processor {
+
+// Field-id-keyed dispatch for TrackEvent extension parsers. Empty registry
+// costs one bool check per packet.
+class TrackEventPluginRegistry {
+ public:
+  using FieldHandler =
+      std::function<void(protozero::ConstBytes data, int64_t ts)>;
+
+  class Plugin {
+   public:
+    virtual ~Plugin();
+  };
+
+  void RegisterFieldHandler(uint32_t field_id, FieldHandler handler) {
+    handlers_.Insert(field_id, std::move(handler));
+  }
+
+  void RegisterPlugin(std::unique_ptr<Plugin> plugin) {
+    plugins_.push_back(std::move(plugin));
+  }
+
+  void Dispatch(protozero::ConstBytes event_bytes, int64_t ts) const {
+    if (handlers_.size() == 0)
+      return;
+    protozero::ProtoDecoder decoder(event_bytes);
+    for (auto f = decoder.ReadField(); f.valid(); f = decoder.ReadField()) {
+      if (auto* h = handlers_.Find(f.id())) {
+        (*h)(f.as_bytes(), ts);
+      }
+    }
+  }
+
+ private:
+  base::FlatHashMap<uint32_t, FieldHandler> handlers_;
+  std::vector<std::unique_ptr<Plugin>> plugins_;
+};
+
+}  // namespace perfetto::trace_processor
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_PLUGIN_H_
diff --git a/src/trace_processor/plugins/storage_tables/storage_tables.cc b/src/trace_processor/plugins/storage_tables/storage_tables.cc
index a4d7cb6..3cb75c0 100644
--- a/src/trace_processor/plugins/storage_tables/storage_tables.cc
+++ b/src/trace_processor/plugins/storage_tables/storage_tables.cc
@@ -158,6 +158,7 @@
     AddDataframe(out, s->mutable_jit_frame_table());
     AddDataframe(out, s->mutable_android_key_events_table());
     AddDataframe(out, s->mutable_android_motion_events_table());
+    AddDataframe(out, s->mutable_android_track_event_process_table());
     AddDataframe(out, s->mutable_android_input_event_dispatch_table());
     AddDataframe(out, s->mutable_inputmethod_clients_table());
     AddDataframe(out, s->mutable_inputmethod_manager_service_table());
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index 9db8894..59a139f 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -369,6 +369,15 @@
     return mutable_table<tables::AndroidMotionEventsTable>();
   }
 
+  const tables::AndroidTrackEventProcessTable&
+  android_track_event_process_table() const {
+    return table<tables::AndroidTrackEventProcessTable>();
+  }
+  tables::AndroidTrackEventProcessTable*
+  mutable_android_track_event_process_table() {
+    return mutable_table<tables::AndroidTrackEventProcessTable>();
+  }
+
   const tables::AndroidInputEventDispatchTable&
   android_input_event_dispatch_table() const {
     return table<tables::AndroidInputEventDispatchTable>();
diff --git a/src/trace_processor/tables/android_tables.py b/src/trace_processor/tables/android_tables.py
index 214f118..bc4fb7b 100644
--- a/src/trace_processor/tables/android_tables.py
+++ b/src/trace_processor/tables/android_tables.py
@@ -29,6 +29,7 @@
 from python.generators.trace_processor_table.public import TableDoc
 from python.generators.trace_processor_table.public import WrappingSqlView
 
+from src.trace_processor.tables.metadata_tables import PROCESS_TABLE
 from src.trace_processor.tables.track_tables import TRACK_TABLE
 
 ANDROID_CPU_PER_UID_TRACK_TABLE = Table(
@@ -368,6 +369,30 @@
     ),
 )
 
+ANDROID_TRACK_EVENT_PROCESS_TABLE = Table(
+    python_module=__file__,
+    class_name='AndroidTrackEventProcessTable',
+    sql_name='__intrinsic_android_track_event_process',
+    columns=[
+        C('upid', CppTableId(PROCESS_TABLE), cpp_access=CppAccess.READ),
+        C('start_ts',
+          CppOptional(CppInt64()),
+          cpp_access=CppAccess.READ_AND_HIGH_PERF_WRITE),
+        C('end_ts',
+          CppOptional(CppInt64()),
+          cpp_access=CppAccess.READ_AND_HIGH_PERF_WRITE),
+    ],
+    tabledoc=TableDoc(
+        doc='Per-process lifecycle from Android framework TrackEvents.',
+        group='Android',
+        columns={
+            'upid': 'The process this row describes.',
+            'start_ts': 'Timestamp of AndroidProcessStartEvent.',
+            'end_ts': 'Timestamp of AndroidBinderDiedEvent.',
+        },
+    ),
+)
+
 # Keep this list sorted.
 ALL_TABLES = [
     ANDROID_AFLAGS_TABLE,
@@ -377,5 +402,6 @@
     ANDROID_INPUT_EVENT_DISPATCH_TABLE,
     ANDROID_KEY_EVENTS_TABLE,
     ANDROID_MOTION_EVENTS_TABLE,
+    ANDROID_TRACK_EVENT_PROCESS_TABLE,
     ANDROID_USER_LIST_TABLE,
 ]