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, ]