1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/proto/track_event_parser.h"
18
19 #include <cstddef>
20 #include <cstdint>
21 #include <optional>
22 #include <string>
23 #include <utility>
24 #include <vector>
25
26 #include "perfetto/base/logging.h"
27 #include "perfetto/base/status.h"
28 #include "perfetto/ext/base/string_view.h"
29 #include "perfetto/ext/base/string_writer.h"
30 #include "perfetto/protozero/field.h"
31 #include "perfetto/protozero/proto_decoder.h"
32 #include "perfetto/public/compiler.h"
33 #include "perfetto/trace_processor/basic_types.h"
34 #include "src/trace_processor/containers/null_term_string_view.h"
35 #include "src/trace_processor/containers/string_pool.h"
36 #include "src/trace_processor/importers/common/args_tracker.h"
37 #include "src/trace_processor/importers/common/args_translation_table.h"
38 #include "src/trace_processor/importers/common/cpu_tracker.h"
39 #include "src/trace_processor/importers/common/event_tracker.h"
40 #include "src/trace_processor/importers/common/flow_tracker.h"
41 #include "src/trace_processor/importers/common/parser_types.h"
42 #include "src/trace_processor/importers/common/process_track_translation_table.h"
43 #include "src/trace_processor/importers/common/process_tracker.h"
44 #include "src/trace_processor/importers/common/track_tracker.h"
45 #include "src/trace_processor/importers/common/tracks.h"
46 #include "src/trace_processor/importers/common/tracks_common.h"
47 #include "src/trace_processor/importers/common/tracks_internal.h"
48 #include "src/trace_processor/importers/common/virtual_memory_mapping.h"
49 #include "src/trace_processor/importers/proto/args_parser.h"
50 #include "src/trace_processor/importers/proto/packet_analyzer.h"
51 #include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
52 #include "src/trace_processor/importers/proto/track_event_tracker.h"
53 #include "src/trace_processor/storage/stats.h"
54 #include "src/trace_processor/storage/trace_storage.h"
55 #include "src/trace_processor/tables/slice_tables_py.h"
56 #include "src/trace_processor/types/variadic.h"
57 #include "src/trace_processor/util/debug_annotation_parser.h"
58 #include "src/trace_processor/util/proto_to_args_parser.h"
59 #include "src/trace_processor/util/status_macros.h"
60
61 #include "protos/perfetto/common/android_log_constants.pbzero.h"
62 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
63 #include "protos/perfetto/trace/track_event/chrome_active_processes.pbzero.h"
64 #include "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h"
65 #include "protos/perfetto/trace/track_event/chrome_histogram_sample.pbzero.h"
66 #include "protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h"
67 #include "protos/perfetto/trace/track_event/chrome_thread_descriptor.pbzero.h"
68 #include "protos/perfetto/trace/track_event/counter_descriptor.pbzero.h"
69 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
70 #include "protos/perfetto/trace/track_event/log_message.pbzero.h"
71 #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
72 #include "protos/perfetto/trace/track_event/source_location.pbzero.h"
73 #include "protos/perfetto/trace/track_event/task_execution.pbzero.h"
74 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
75 #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
76 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
77
78 namespace perfetto::trace_processor {
79
80 namespace {
81 using BoundInserter = ArgsTracker::BoundInserter;
82 using protos::pbzero::TrackEvent;
83 using LegacyEvent = TrackEvent::LegacyEvent;
84 using protozero::ConstBytes;
85
86 // Slices which have been opened but haven't been closed yet will be marked
87 // with these placeholder values.
88 constexpr int64_t kPendingThreadDuration = -1;
89 constexpr int64_t kPendingThreadInstructionDelta = -1;
90
91 // Paths on Windows use backslash rather than slash as a separator.
92 // Normalise the paths by replacing backslashes with slashes to make it
93 // easier to write cross-platform scripts.
NormalizePathSeparators(const protozero::ConstChars & path)94 std::string NormalizePathSeparators(const protozero::ConstChars& path) {
95 std::string result(path.data, path.size);
96 for (char& c : result) {
97 if (c == '\\')
98 c = '/';
99 }
100 return result;
101 }
102
MaybeParseUnsymbolizedSourceLocation(const std::string & prefix,const protozero::Field & field,util::ProtoToArgsParser::Delegate & delegate)103 std::optional<base::Status> MaybeParseUnsymbolizedSourceLocation(
104 const std::string& prefix,
105 const protozero::Field& field,
106 util::ProtoToArgsParser::Delegate& delegate) {
107 auto* decoder = delegate.GetInternedMessage(
108 protos::pbzero::InternedData::kUnsymbolizedSourceLocations,
109 field.as_uint64());
110 if (!decoder) {
111 // Lookup failed fall back on default behaviour which will just put
112 // the iid into the args table.
113 return std::nullopt;
114 }
115 // Interned mapping_id loses it's meaning when the sequence ends. So we need
116 // to get an id from stack_profile_mapping table.
117 auto* mapping = delegate.seq_state()
118 ->GetCustomState<StackProfileSequenceState>()
119 ->FindOrInsertMapping(decoder->mapping_id());
120 if (!mapping) {
121 return std::nullopt;
122 }
123 delegate.AddUnsignedInteger(
124 util::ProtoToArgsParser::Key(prefix + ".mapping_id"),
125 mapping->mapping_id().value);
126 delegate.AddUnsignedInteger(util::ProtoToArgsParser::Key(prefix + ".rel_pc"),
127 decoder->rel_pc());
128 return base::OkStatus();
129 }
130
MaybeParseSourceLocation(const std::string & prefix,const protozero::Field & field,util::ProtoToArgsParser::Delegate & delegate)131 std::optional<base::Status> MaybeParseSourceLocation(
132 const std::string& prefix,
133 const protozero::Field& field,
134 util::ProtoToArgsParser::Delegate& delegate) {
135 auto* decoder = delegate.GetInternedMessage(
136 protos::pbzero::InternedData::kSourceLocations, field.as_uint64());
137 if (!decoder) {
138 // Lookup failed fall back on default behaviour which will just put
139 // the source_location_iid into the args table.
140 return std::nullopt;
141 }
142
143 delegate.AddString(util::ProtoToArgsParser::Key(prefix + ".file_name"),
144 NormalizePathSeparators(decoder->file_name()));
145 delegate.AddString(util::ProtoToArgsParser::Key(prefix + ".function_name"),
146 decoder->function_name());
147 if (decoder->has_line_number()) {
148 delegate.AddInteger(util::ProtoToArgsParser::Key(prefix + ".line_number"),
149 decoder->line_number());
150 }
151 return base::OkStatus();
152 }
153
ToAndroidLogPriority(protos::pbzero::LogMessage::Priority prio)154 protos::pbzero::AndroidLogPriority ToAndroidLogPriority(
155 protos::pbzero::LogMessage::Priority prio) {
156 switch (prio) {
157 case protos::pbzero::LogMessage::Priority::PRIO_UNSPECIFIED:
158 return protos::pbzero::AndroidLogPriority::PRIO_UNSPECIFIED;
159 case protos::pbzero::LogMessage::Priority::PRIO_UNUSED:
160 return protos::pbzero::AndroidLogPriority::PRIO_UNUSED;
161 case protos::pbzero::LogMessage::Priority::PRIO_VERBOSE:
162 return protos::pbzero::AndroidLogPriority::PRIO_VERBOSE;
163 case protos::pbzero::LogMessage::Priority::PRIO_DEBUG:
164 return protos::pbzero::AndroidLogPriority::PRIO_DEBUG;
165 case protos::pbzero::LogMessage::Priority::PRIO_INFO:
166 return protos::pbzero::AndroidLogPriority::PRIO_INFO;
167 case protos::pbzero::LogMessage::Priority::PRIO_WARN:
168 return protos::pbzero::AndroidLogPriority::PRIO_WARN;
169 case protos::pbzero::LogMessage::Priority::PRIO_ERROR:
170 return protos::pbzero::AndroidLogPriority::PRIO_ERROR;
171 case protos::pbzero::LogMessage::Priority::PRIO_FATAL:
172 return protos::pbzero::AndroidLogPriority::PRIO_FATAL;
173 }
174 return protos::pbzero::AndroidLogPriority::PRIO_UNSPECIFIED;
175 }
176
177 } // namespace
178
179 class TrackEventParser::EventImporter {
180 public:
EventImporter(TrackEventParser * parser,int64_t ts,const TrackEventData * event_data,ConstBytes blob,uint32_t packet_sequence_id)181 EventImporter(TrackEventParser* parser,
182 int64_t ts,
183 const TrackEventData* event_data,
184 ConstBytes blob,
185 uint32_t packet_sequence_id)
186 : context_(parser->context_),
187 track_event_tracker_(parser->track_event_tracker_),
188 storage_(context_->storage.get()),
189 parser_(parser),
190 args_translation_table_(context_->args_translation_table.get()),
191 ts_(ts),
192 event_data_(event_data),
193 sequence_state_(event_data->trace_packet_data.sequence_state.get()),
194 blob_(blob),
195 event_(blob_),
196 legacy_event_(event_.legacy_event()),
197 defaults_(event_data->trace_packet_data.sequence_state
198 ->GetTrackEventDefaults()),
199 thread_timestamp_(event_data->thread_timestamp),
200 thread_instruction_count_(event_data->thread_instruction_count),
201 packet_sequence_id_(packet_sequence_id) {}
202
Import()203 base::Status Import() {
204 // TODO(eseckler): This legacy event field will eventually be replaced by
205 // fields in TrackEvent itself.
206 if (PERFETTO_UNLIKELY(!event_.type() && !legacy_event_.has_phase()))
207 return base::ErrStatus("TrackEvent without type or phase");
208
209 category_id_ = ParseTrackEventCategory();
210 name_id_ = ParseTrackEventName();
211
212 if (context_->content_analyzer) {
213 PacketAnalyzer::SampleAnnotation annotation;
214 annotation.emplace_back(parser_->event_category_key_id_, category_id_);
215 annotation.emplace_back(parser_->event_name_key_id_, name_id_);
216 PacketAnalyzer::Get(context_)->ProcessPacket(
217 event_data_->trace_packet_data.packet, annotation);
218 }
219
220 RETURN_IF_ERROR(ParseTrackAssociation());
221
222 // If we have legacy thread time / instruction count fields, also parse them
223 // into the counters tables.
224 ParseLegacyThreadTimeAndInstructionsAsCounters();
225
226 // Parse extra counter values before parsing the actual event. This way, we
227 // can update the slice's thread time / instruction count fields based on
228 // these counter values and also parse them as slice attributes / arguments.
229 ParseExtraCounterValues();
230
231 // Non-legacy counters are treated differently. Legacy counters do not have
232 // a track_id_ and should instead go through the switch below.
233 if (event_.type() == TrackEvent::TYPE_COUNTER) {
234 return ParseCounterEvent();
235 }
236
237 // TODO(eseckler): Replace phase with type and remove handling of
238 // legacy_event_.phase() once it is no longer used by producers.
239 char phase = static_cast<char>(ParsePhaseOrType());
240
241 switch (phase) {
242 case 'B': // TRACE_EVENT_PHASE_BEGIN.
243 return ParseThreadBeginEvent();
244 case 'E': // TRACE_EVENT_PHASE_END.
245 return ParseThreadEndEvent();
246 case 'X': // TRACE_EVENT_PHASE_COMPLETE.
247 return ParseThreadCompleteEvent();
248 case 's': // TRACE_EVENT_PHASE_FLOW_BEGIN.
249 case 't': // TRACE_EVENT_PHASE_FLOW_STEP.
250 case 'f': // TRACE_EVENT_PHASE_FLOW_END.
251 return ParseFlowEventV1(phase);
252 case 'i':
253 case 'I': // TRACE_EVENT_PHASE_INSTANT.
254 case 'R': // TRACE_EVENT_PHASE_MARK.
255 return ParseThreadInstantEvent(phase);
256 case 'b': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN
257 case 'S':
258 return ParseAsyncBeginEvent(phase);
259 case 'e': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_END
260 case 'F':
261 return ParseAsyncEndEvent();
262 case 'n': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT
263 return ParseAsyncInstantEvent();
264 case 'T':
265 case 'p':
266 return ParseAsyncStepEvent(phase);
267 case 'M': // TRACE_EVENT_PHASE_METADATA (process and thread names).
268 return ParseMetadataEvent();
269 default:
270 // Other events are proxied via the raw table for JSON export.
271 return ParseLegacyEventAsRawEvent();
272 }
273 }
274
275 private:
ParseTrackEventCategory()276 StringId ParseTrackEventCategory() {
277 StringId category_id = kNullStringId;
278
279 std::vector<uint64_t> category_iids;
280 for (auto it = event_.category_iids(); it; ++it) {
281 category_iids.push_back(*it);
282 }
283 std::vector<protozero::ConstChars> category_strings;
284 for (auto it = event_.categories(); it; ++it) {
285 category_strings.push_back(*it);
286 }
287
288 // If there's a single category, we can avoid building a concatenated
289 // string.
290 if (PERFETTO_LIKELY(category_iids.size() == 1 &&
291 category_strings.empty())) {
292 auto* decoder = sequence_state_->LookupInternedMessage<
293 protos::pbzero::InternedData::kEventCategoriesFieldNumber,
294 protos::pbzero::EventCategory>(category_iids[0]);
295 if (decoder) {
296 category_id = storage_->InternString(decoder->name());
297 } else {
298 char buffer[32];
299 base::StringWriter writer(buffer, sizeof(buffer));
300 writer.AppendLiteral("unknown(");
301 writer.AppendUnsignedInt(category_iids[0]);
302 writer.AppendChar(')');
303 category_id = storage_->InternString(writer.GetStringView());
304 }
305 } else if (category_iids.empty() && category_strings.size() == 1) {
306 category_id = storage_->InternString(category_strings[0]);
307 } else if (category_iids.size() + category_strings.size() > 1) {
308 // We concatenate the category strings together since we currently only
309 // support a single "cat" column.
310 // TODO(eseckler): Support multi-category events in the table schema.
311 std::string categories;
312 for (uint64_t iid : category_iids) {
313 auto* decoder = sequence_state_->LookupInternedMessage<
314 protos::pbzero::InternedData::kEventCategoriesFieldNumber,
315 protos::pbzero::EventCategory>(iid);
316 if (!decoder)
317 continue;
318 base::StringView name = decoder->name();
319 if (!categories.empty())
320 categories.append(",");
321 categories.append(name.data(), name.size());
322 }
323 for (const protozero::ConstChars& cat : category_strings) {
324 if (!categories.empty())
325 categories.append(",");
326 categories.append(cat.data, cat.size);
327 }
328 if (!categories.empty())
329 category_id = storage_->InternString(base::StringView(categories));
330 }
331
332 return category_id;
333 }
334
ParseTrackEventName()335 StringId ParseTrackEventName() {
336 uint64_t name_iid = event_.name_iid();
337 if (!name_iid)
338 name_iid = legacy_event_.name_iid();
339
340 if (PERFETTO_LIKELY(name_iid)) {
341 auto* decoder = sequence_state_->LookupInternedMessage<
342 protos::pbzero::InternedData::kEventNamesFieldNumber,
343 protos::pbzero::EventName>(name_iid);
344 if (decoder)
345 return storage_->InternString(decoder->name());
346 } else if (event_.has_name()) {
347 return storage_->InternString(event_.name());
348 }
349
350 return kNullStringId;
351 }
352
ParseTrackAssociation()353 base::Status ParseTrackAssociation() {
354 TrackTracker* track_tracker = context_->track_tracker.get();
355 ProcessTracker* procs = context_->process_tracker.get();
356
357 // Consider track_uuid from the packet and TrackEventDefaults, fall back to
358 // the default descriptor track (uuid 0).
359 track_uuid_ = event_.has_track_uuid()
360 ? event_.track_uuid()
361 : (defaults_ && defaults_->has_track_uuid()
362 ? defaults_->track_uuid()
363 : 0u);
364
365 // Determine track from track_uuid specified in either TrackEvent or
366 // TrackEventDefaults. If a non-default track is not set, we either:
367 // a) fall back to the track specified by the sequence's (or event's) pid
368 // + tid (only in case of legacy tracks/events, i.e. events that don't
369 // specify an explicit track uuid or use legacy event phases instead of
370 // TrackEvent types), or
371 // b) a default track.
372 if (track_uuid_) {
373 std::optional<TrackId> opt_track_id =
374 track_event_tracker_->GetDescriptorTrack(track_uuid_, name_id_,
375 packet_sequence_id_);
376 if (!opt_track_id) {
377 TrackEventTracker::DescriptorTrackReservation r;
378 r.parent_uuid = 0;
379 r.name = name_id_;
380 track_event_tracker_->ReserveDescriptorTrack(track_uuid_, r);
381 opt_track_id = track_event_tracker_->GetDescriptorTrack(
382 track_uuid_, name_id_, packet_sequence_id_);
383 }
384 track_id_ = *opt_track_id;
385
386 auto tt_rr = storage_->thread_track_table().FindById(track_id_);
387 if (tt_rr) {
388 utid_ = tt_rr->utid();
389 upid_ = storage_->thread_table()[*utid_].upid();
390 } else {
391 auto pt_rr = storage_->process_track_table().FindById(track_id_);
392 if (pt_rr) {
393 upid_ = pt_rr->upid();
394 if (sequence_state_->pid_and_tid_valid()) {
395 auto pid = static_cast<uint32_t>(sequence_state_->pid());
396 auto tid = static_cast<uint32_t>(sequence_state_->tid());
397 UniqueTid utid_candidate = procs->UpdateThread(tid, pid);
398 if (storage_->thread_table()[utid_candidate].upid() == upid_) {
399 legacy_passthrough_utid_ = utid_candidate;
400 }
401 }
402 } else {
403 auto* tracks = context_->storage->mutable_track_table();
404 auto t_rr = tracks->FindById(track_id_);
405 if (t_rr) {
406 StringPool::Id id = t_rr->name();
407 if (id.is_null()) {
408 t_rr->set_name(name_id_);
409 }
410 }
411 if (sequence_state_->pid_and_tid_valid()) {
412 auto pid = static_cast<uint32_t>(sequence_state_->pid());
413 auto tid = static_cast<uint32_t>(sequence_state_->tid());
414 legacy_passthrough_utid_ = procs->UpdateThread(tid, pid);
415 }
416 }
417 }
418 } else {
419 bool pid_tid_state_valid = sequence_state_->pid_and_tid_valid();
420
421 // We have a 0-value |track_uuid|. Nevertheless, we should only fall back
422 // if we have either no |track_uuid| specified at all or |track_uuid| was
423 // set explicitly to 0 (e.g. to override a default track_uuid) and we have
424 // a legacy phase. Events with real phases should use |track_uuid| to
425 // specify a different track (or use the pid/tid_override fields).
426 bool fallback_to_legacy_pid_tid_tracks =
427 (!event_.has_track_uuid() || !event_.has_type()) &&
428 pid_tid_state_valid;
429
430 // Always allow fallback if we have a process override.
431 fallback_to_legacy_pid_tid_tracks |= legacy_event_.has_pid_override();
432
433 // A thread override requires a valid pid.
434 fallback_to_legacy_pid_tid_tracks |=
435 legacy_event_.has_tid_override() && pid_tid_state_valid;
436
437 if (fallback_to_legacy_pid_tid_tracks) {
438 auto pid = static_cast<uint32_t>(sequence_state_->pid());
439 auto tid = static_cast<uint32_t>(sequence_state_->tid());
440 if (legacy_event_.has_pid_override()) {
441 pid = static_cast<uint32_t>(legacy_event_.pid_override());
442 tid = static_cast<uint32_t>(-1);
443 }
444 if (legacy_event_.has_tid_override())
445 tid = static_cast<uint32_t>(legacy_event_.tid_override());
446
447 utid_ = procs->UpdateThread(tid, pid);
448 upid_ = storage_->thread_table()[*utid_].upid();
449 track_id_ = track_tracker->InternThreadTrack(*utid_);
450 } else {
451 track_id_ = track_event_tracker_->GetOrCreateDefaultDescriptorTrack();
452 }
453 }
454
455 if (!legacy_event_.has_phase())
456 return base::OkStatus();
457
458 // Legacy phases may imply a different track than the one specified by
459 // the fallback (or default track uuid) above.
460 switch (legacy_event_.phase()) {
461 case 'b':
462 case 'e':
463 case 'n':
464 case 'S':
465 case 'T':
466 case 'p':
467 case 'F': {
468 // Intern tracks for legacy async events based on legacy event ids.
469 int64_t source_id = 0;
470 bool source_id_is_process_scoped = false;
471 if (legacy_event_.has_unscoped_id()) {
472 source_id = static_cast<int64_t>(legacy_event_.unscoped_id());
473 } else if (legacy_event_.has_global_id()) {
474 source_id = static_cast<int64_t>(legacy_event_.global_id());
475 } else if (legacy_event_.has_local_id()) {
476 if (!upid_) {
477 return base::ErrStatus(
478 "TrackEvent with local_id without process association");
479 }
480
481 source_id = static_cast<int64_t>(legacy_event_.local_id());
482 source_id_is_process_scoped = true;
483 } else {
484 return base::ErrStatus("Async LegacyEvent without ID");
485 }
486
487 // Catapult treats nestable async events of different categories with
488 // the same ID as separate tracks. We replicate the same behavior
489 // here. For legacy async events, it uses different tracks based on
490 // event names.
491 const bool legacy_async =
492 legacy_event_.phase() == 'S' || legacy_event_.phase() == 'T' ||
493 legacy_event_.phase() == 'p' || legacy_event_.phase() == 'F';
494 StringId id_scope = legacy_async ? name_id_ : category_id_;
495 if (legacy_event_.has_id_scope()) {
496 std::string concat = storage_->GetString(category_id_).ToStdString() +
497 ":" + legacy_event_.id_scope().ToStdString();
498 id_scope = storage_->InternString(base::StringView(concat));
499 }
500
501 track_id_ = context_->track_tracker->LegacyInternLegacyChromeAsyncTrack(
502 name_id_, upid_.value_or(0), source_id, source_id_is_process_scoped,
503 id_scope);
504 legacy_passthrough_utid_ = utid_;
505 break;
506 }
507 case 'i':
508 case 'I': {
509 // Intern tracks for global or process-scoped legacy instant events.
510 switch (legacy_event_.instant_event_scope()) {
511 case LegacyEvent::SCOPE_UNSPECIFIED:
512 case LegacyEvent::SCOPE_THREAD:
513 // Thread-scoped legacy instant events already have the right
514 // track based on the tid/pid of the sequence.
515 if (!utid_) {
516 return base::ErrStatus(
517 "Thread-scoped instant event without thread association");
518 }
519 break;
520 case LegacyEvent::SCOPE_GLOBAL:
521 track_id_ = context_->track_tracker->InternTrack(
522 tracks::kLegacyGlobalInstantsBlueprint, tracks::Dimensions(),
523 tracks::BlueprintName(),
524 [this](ArgsTracker::BoundInserter& inserter) {
525 inserter.AddArg(
526 context_->storage->InternString("source"),
527 Variadic::String(
528 context_->storage->InternString("chrome")));
529 });
530 legacy_passthrough_utid_ = utid_;
531 utid_ = std::nullopt;
532 break;
533 case LegacyEvent::SCOPE_PROCESS:
534 if (!upid_) {
535 return base::ErrStatus(
536 "Process-scoped instant event without process association");
537 }
538
539 track_id_ = context_->track_tracker->InternProcessTrack(
540 tracks::chrome_process_instant, *upid_);
541 context_->args_tracker->AddArgsTo(track_id_).AddArg(
542 context_->storage->InternString("source"),
543 Variadic::String(context_->storage->InternString("chrome")));
544 legacy_passthrough_utid_ = utid_;
545 utid_ = std::nullopt;
546 break;
547 }
548 break;
549 }
550 default:
551 break;
552 }
553
554 return base::OkStatus();
555 }
556
ParsePhaseOrType()557 int32_t ParsePhaseOrType() {
558 if (legacy_event_.has_phase())
559 return legacy_event_.phase();
560
561 switch (event_.type()) {
562 case TrackEvent::TYPE_SLICE_BEGIN:
563 return utid_ ? 'B' : 'b';
564 case TrackEvent::TYPE_SLICE_END:
565 return utid_ ? 'E' : 'e';
566 case TrackEvent::TYPE_INSTANT:
567 return utid_ ? 'i' : 'n';
568 default:
569 PERFETTO_ELOG("unexpected event type %d", event_.type());
570 return 0;
571 }
572 }
573
ParseCounterEvent()574 base::Status ParseCounterEvent() {
575 // Tokenizer ensures that TYPE_COUNTER events are associated with counter
576 // tracks and have values.
577 PERFETTO_DCHECK(storage_->track_table().FindById(track_id_));
578 PERFETTO_DCHECK(event_.has_counter_value() ||
579 event_.has_double_counter_value());
580
581 context_->event_tracker->PushCounter(
582 ts_, static_cast<double>(event_data_->counter_value), track_id_,
583 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
584 return base::OkStatus();
585 }
586
ParseLegacyThreadTimeAndInstructionsAsCounters()587 void ParseLegacyThreadTimeAndInstructionsAsCounters() {
588 if (!utid_)
589 return;
590 // When these fields are set, we don't expect TrackDescriptor-based counters
591 // for thread time or instruction count for this thread in the trace, so we
592 // intern separate counter tracks based on name + utid. Note that we cannot
593 // import the counter values from the end of a complete event, because the
594 // EventTracker expects counters to be pushed in order of their timestamps.
595 // One more reason to switch to split begin/end events.
596 if (thread_timestamp_) {
597 static constexpr auto kBlueprint = tracks::CounterBlueprint(
598 "thread_time", tracks::UnknownUnitBlueprint(),
599 tracks::DimensionBlueprints(tracks::kThreadDimensionBlueprint),
600 tracks::DynamicNameBlueprint());
601 TrackId track_id = context_->track_tracker->InternTrack(
602 kBlueprint, tracks::Dimensions(*utid_),
603 tracks::DynamicName(parser_->counter_name_thread_time_id_));
604 context_->event_tracker->PushCounter(
605 ts_, static_cast<double>(*thread_timestamp_), track_id);
606 }
607 if (thread_instruction_count_) {
608 static constexpr auto kBlueprint = tracks::CounterBlueprint(
609 "thread_instructions", tracks::UnknownUnitBlueprint(),
610 tracks::DimensionBlueprints(tracks::kThreadDimensionBlueprint),
611 tracks::DynamicNameBlueprint());
612 TrackId track_id = context_->track_tracker->InternTrack(
613 kBlueprint, tracks::Dimensions(*utid_),
614 tracks::DynamicName(
615 parser_->counter_name_thread_instruction_count_id_));
616 context_->event_tracker->PushCounter(
617 ts_, static_cast<double>(*thread_instruction_count_), track_id);
618 }
619 }
620
ParseExtraCounterValues()621 void ParseExtraCounterValues() {
622 if (!event_.has_extra_counter_values() &&
623 !event_.has_extra_double_counter_values()) {
624 return;
625 }
626
627 // Add integer extra counter values.
628 size_t index = 0;
629 protozero::RepeatedFieldIterator<uint64_t> track_uuid_it;
630 if (event_.has_extra_counter_track_uuids()) {
631 track_uuid_it = event_.extra_counter_track_uuids();
632 } else if (defaults_ && defaults_->has_extra_counter_track_uuids()) {
633 track_uuid_it = defaults_->extra_counter_track_uuids();
634 }
635 for (auto value_it = event_.extra_counter_values(); value_it;
636 ++value_it, ++track_uuid_it, ++index) {
637 AddExtraCounterValue(track_uuid_it, index);
638 }
639
640 // Add double extra counter values.
641 track_uuid_it = protozero::RepeatedFieldIterator<uint64_t>();
642 if (event_.has_extra_double_counter_track_uuids()) {
643 track_uuid_it = event_.extra_double_counter_track_uuids();
644 } else if (defaults_ && defaults_->has_extra_double_counter_track_uuids()) {
645 track_uuid_it = defaults_->extra_double_counter_track_uuids();
646 }
647 for (auto value_it = event_.extra_double_counter_values(); value_it;
648 ++value_it, ++track_uuid_it, ++index) {
649 AddExtraCounterValue(track_uuid_it, index);
650 }
651 }
652
AddExtraCounterValue(protozero::RepeatedFieldIterator<uint64_t> track_uuid_it,size_t index)653 void AddExtraCounterValue(
654 protozero::RepeatedFieldIterator<uint64_t> track_uuid_it,
655 size_t index) {
656 // Tokenizer ensures that there aren't more values than uuids, that we
657 // don't have more values than kMaxNumExtraCounters and that the
658 // track_uuids are for valid counter tracks.
659 PERFETTO_DCHECK(track_uuid_it);
660 PERFETTO_DCHECK(index < TrackEventData::kMaxNumExtraCounters);
661
662 std::optional<TrackId> track_id = track_event_tracker_->GetDescriptorTrack(
663 *track_uuid_it, kNullStringId, packet_sequence_id_);
664 auto counter_row = storage_->track_table().FindById(*track_id);
665
666 double value = event_data_->extra_counter_values[index];
667 context_->event_tracker->PushCounter(ts_, value, *track_id);
668
669 // Also import thread_time and thread_instruction_count counters into
670 // slice columns to simplify JSON export.
671 StringId counter_name = counter_row->name();
672 if (counter_name == parser_->counter_name_thread_time_id_) {
673 thread_timestamp_ = static_cast<int64_t>(value);
674 } else if (counter_name ==
675 parser_->counter_name_thread_instruction_count_id_) {
676 thread_instruction_count_ = static_cast<int64_t>(value);
677 }
678 }
679
ParseThreadBeginEvent()680 base::Status ParseThreadBeginEvent() {
681 if (!utid_) {
682 return base::ErrStatus(
683 "TrackEvent with phase B without thread association");
684 }
685
686 auto* thread_slices = storage_->mutable_slice_table();
687 auto opt_slice_id = context_->slice_tracker->BeginTyped(
688 thread_slices, MakeThreadSliceRow(),
689 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
690
691 if (opt_slice_id.has_value()) {
692 MaybeParseFlowEvents(opt_slice_id.value());
693 }
694 return base::OkStatus();
695 }
696
ParseThreadEndEvent()697 base::Status ParseThreadEndEvent() {
698 if (!utid_) {
699 return base::ErrStatus(
700 "TrackEvent with phase E without thread association");
701 }
702 auto opt_slice_id = context_->slice_tracker->End(
703 ts_, track_id_, category_id_, name_id_,
704 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
705 if (!opt_slice_id)
706 return base::OkStatus();
707
708 MaybeParseFlowEvents(*opt_slice_id);
709 auto* thread_slices = storage_->mutable_slice_table();
710 auto opt_thread_slice_ref = thread_slices->FindById(*opt_slice_id);
711 if (!opt_thread_slice_ref) {
712 // This means that the end event did not match a corresponding track event
713 // begin packet so we likely closed the wrong slice. There's not much we
714 // can do about this beyond flag it as a stat.
715 context_->storage->IncrementStats(stats::track_event_thread_invalid_end);
716 return base::OkStatus();
717 }
718
719 tables::SliceTable::RowReference slice_ref = *opt_thread_slice_ref;
720 std::optional<int64_t> tts = slice_ref.thread_ts();
721 if (tts) {
722 PERFETTO_DCHECK(thread_timestamp_);
723 slice_ref.set_thread_dur(*thread_timestamp_ - *tts);
724 }
725 std::optional<int64_t> tic = slice_ref.thread_instruction_count();
726 if (tic) {
727 PERFETTO_DCHECK(event_data_->thread_instruction_count);
728 slice_ref.set_thread_instruction_delta(
729 *event_data_->thread_instruction_count - *tic);
730 }
731 return base::OkStatus();
732 }
733
ParseThreadCompleteEvent()734 base::Status ParseThreadCompleteEvent() {
735 if (!utid_) {
736 return base::ErrStatus(
737 "TrackEvent with phase X without thread association");
738 }
739
740 auto duration_ns = legacy_event_.duration_us() * 1000;
741 if (duration_ns < 0)
742 return base::ErrStatus("TrackEvent with phase X with negative duration");
743
744 auto* thread_slices = storage_->mutable_slice_table();
745 tables::SliceTable::Row row = MakeThreadSliceRow();
746 row.dur = duration_ns;
747 if (legacy_event_.has_thread_duration_us()) {
748 row.thread_dur = legacy_event_.thread_duration_us() * 1000;
749 }
750 if (legacy_event_.has_thread_instruction_delta()) {
751 row.thread_instruction_delta = legacy_event_.thread_instruction_delta();
752 }
753 auto opt_slice_id = context_->slice_tracker->ScopedTyped(
754 thread_slices, row,
755 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
756
757 if (opt_slice_id.has_value()) {
758 MaybeParseFlowEvents(opt_slice_id.value());
759 }
760 return base::OkStatus();
761 }
762
GetLegacyEventId()763 std::optional<uint64_t> GetLegacyEventId() {
764 if (legacy_event_.has_unscoped_id())
765 return legacy_event_.unscoped_id();
766 // TODO(andrewbb): Catapult doesn't support global_id and local_id on flow
767 // events. We could add support in trace processor (e.g. because there seem
768 // to be some callsites supplying local_id in chromium), but we would have
769 // to consider the process ID for local IDs and use a separate ID scope for
770 // global_id and unscoped_id.
771 return std::nullopt;
772 }
773
ParseFlowEventV1(char phase)774 base::Status ParseFlowEventV1(char phase) {
775 auto opt_source_id = GetLegacyEventId();
776 if (!opt_source_id) {
777 storage_->IncrementStats(stats::flow_invalid_id);
778 return base::ErrStatus("Invalid id for flow event v1");
779 }
780 FlowId flow_id = context_->flow_tracker->GetFlowIdForV1Event(
781 opt_source_id.value(), category_id_, name_id_);
782 switch (phase) {
783 case 's':
784 context_->flow_tracker->Begin(track_id_, flow_id);
785 break;
786 case 't':
787 context_->flow_tracker->Step(track_id_, flow_id);
788 break;
789 case 'f':
790 context_->flow_tracker->End(track_id_, flow_id,
791 legacy_event_.bind_to_enclosing(),
792 /* close_flow = */ false);
793 break;
794 }
795 return base::OkStatus();
796 }
797
MaybeParseTrackEventFlows(SliceId slice_id)798 void MaybeParseTrackEventFlows(SliceId slice_id) {
799 if (event_.has_flow_ids_old() || event_.has_flow_ids()) {
800 auto it =
801 event_.has_flow_ids() ? event_.flow_ids() : event_.flow_ids_old();
802 for (; it; ++it) {
803 FlowId flow_id = *it;
804 if (!context_->flow_tracker->IsActive(flow_id)) {
805 context_->flow_tracker->Begin(slice_id, flow_id);
806 continue;
807 }
808 context_->flow_tracker->Step(slice_id, flow_id);
809 }
810 }
811 if (event_.has_terminating_flow_ids_old() ||
812 event_.has_terminating_flow_ids()) {
813 auto it = event_.has_terminating_flow_ids()
814 ? event_.terminating_flow_ids()
815 : event_.terminating_flow_ids_old();
816 for (; it; ++it) {
817 FlowId flow_id = *it;
818 if (!context_->flow_tracker->IsActive(flow_id)) {
819 // If we should terminate a flow, do not begin a new one if it's not
820 // active already.
821 continue;
822 }
823 context_->flow_tracker->End(slice_id, flow_id,
824 /* close_flow = */ true);
825 }
826 }
827 }
828
MaybeParseFlowEventV2(SliceId slice_id)829 void MaybeParseFlowEventV2(SliceId slice_id) {
830 if (!legacy_event_.has_bind_id()) {
831 return;
832 }
833 if (!legacy_event_.has_flow_direction()) {
834 storage_->IncrementStats(stats::flow_without_direction);
835 return;
836 }
837
838 auto bind_id = legacy_event_.bind_id();
839 switch (legacy_event_.flow_direction()) {
840 case LegacyEvent::FLOW_OUT:
841 context_->flow_tracker->Begin(slice_id, bind_id);
842 break;
843 case LegacyEvent::FLOW_INOUT:
844 context_->flow_tracker->Step(slice_id, bind_id);
845 break;
846 case LegacyEvent::FLOW_IN:
847 context_->flow_tracker->End(slice_id, bind_id,
848 /* close_flow = */ false);
849 break;
850 default:
851 storage_->IncrementStats(stats::flow_without_direction);
852 }
853 }
854
MaybeParseFlowEvents(SliceId slice_id)855 void MaybeParseFlowEvents(SliceId slice_id) {
856 MaybeParseFlowEventV2(slice_id);
857 MaybeParseTrackEventFlows(slice_id);
858 }
859
ParseThreadInstantEvent(char phase)860 base::Status ParseThreadInstantEvent(char phase) {
861 // Handle instant events as slices with zero duration, so that they end
862 // up nested underneath their parent slices.
863 int64_t duration_ns = 0;
864 int64_t tidelta = 0;
865 std::optional<tables::SliceTable::Id> opt_slice_id;
866 auto args_inserter = [this, phase](BoundInserter* inserter) {
867 ParseTrackEventArgs(inserter);
868 // For legacy MARK event, add phase for JSON exporter.
869 if (phase == 'R') {
870 std::string phase_string(1, static_cast<char>(phase));
871 StringId phase_id = storage_->InternString(phase_string.c_str());
872 inserter->AddArg(parser_->legacy_event_phase_key_id_,
873 Variadic::String(phase_id));
874 }
875 };
876 if (utid_) {
877 auto* thread_slices = storage_->mutable_slice_table();
878 tables::SliceTable::Row row = MakeThreadSliceRow();
879 row.dur = duration_ns;
880 if (thread_timestamp_) {
881 row.thread_dur = duration_ns;
882 }
883 if (thread_instruction_count_) {
884 row.thread_instruction_delta = tidelta;
885 }
886 opt_slice_id = context_->slice_tracker->ScopedTyped(
887 thread_slices, row, std::move(args_inserter));
888 } else {
889 opt_slice_id = context_->slice_tracker->Scoped(
890 ts_, track_id_, category_id_, name_id_, duration_ns,
891 std::move(args_inserter));
892 }
893 if (!opt_slice_id.has_value()) {
894 return base::OkStatus();
895 }
896 MaybeParseFlowEvents(opt_slice_id.value());
897 return base::OkStatus();
898 }
899
ParseAsyncBeginEvent(char phase)900 base::Status ParseAsyncBeginEvent(char phase) {
901 auto args_inserter = [this, phase](BoundInserter* inserter) {
902 ParseTrackEventArgs(inserter);
903
904 if (phase == 'b')
905 return;
906 PERFETTO_DCHECK(phase == 'S');
907 // For legacy ASYNC_BEGIN, add phase for JSON exporter.
908 std::string phase_string(1, static_cast<char>(phase));
909 StringId phase_id = storage_->InternString(phase_string.c_str());
910 inserter->AddArg(parser_->legacy_event_phase_key_id_,
911 Variadic::String(phase_id));
912 };
913 auto opt_slice_id = context_->slice_tracker->Begin(
914 ts_, track_id_, category_id_, name_id_, args_inserter);
915 if (!opt_slice_id.has_value()) {
916 return base::OkStatus();
917 }
918 MaybeParseFlowEvents(opt_slice_id.value());
919 // For the time being, we only create vtrack slice rows if we need to
920 // store thread timestamps/counters.
921 if (legacy_event_.use_async_tts()) {
922 auto* vtrack_slices = storage_->mutable_virtual_track_slices();
923 PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
924 vtrack_slices->slice_ids().back() < opt_slice_id.value());
925 int64_t tts = thread_timestamp_.value_or(0);
926 int64_t tic = thread_instruction_count_.value_or(0);
927 vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
928 kPendingThreadDuration, tic,
929 kPendingThreadInstructionDelta);
930 }
931 return base::OkStatus();
932 }
933
ParseAsyncEndEvent()934 base::Status ParseAsyncEndEvent() {
935 auto opt_slice_id = context_->slice_tracker->End(
936 ts_, track_id_, category_id_, name_id_,
937 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
938 if (!opt_slice_id)
939 return base::OkStatus();
940
941 MaybeParseFlowEvents(*opt_slice_id);
942 if (legacy_event_.use_async_tts()) {
943 auto* vtrack_slices = storage_->mutable_virtual_track_slices();
944 int64_t tts = event_data_->thread_timestamp.value_or(0);
945 int64_t tic = event_data_->thread_instruction_count.value_or(0);
946 vtrack_slices->UpdateThreadDeltasForSliceId(*opt_slice_id, tts, tic);
947 }
948 return base::OkStatus();
949 }
950
ParseAsyncStepEvent(char phase)951 base::Status ParseAsyncStepEvent(char phase) {
952 // Parse step events as instant events. Reconstructing the begin/end times
953 // of the child slice would be too complicated, see b/178540838. For JSON
954 // export, we still record the original step's phase in an arg.
955 int64_t duration_ns = 0;
956 context_->slice_tracker->Scoped(
957 ts_, track_id_, category_id_, name_id_, duration_ns,
958 [this, phase](BoundInserter* inserter) {
959 ParseTrackEventArgs(inserter);
960
961 PERFETTO_DCHECK(phase == 'T' || phase == 'p');
962 std::string phase_string(1, static_cast<char>(phase));
963 StringId phase_id = storage_->InternString(phase_string.c_str());
964 inserter->AddArg(parser_->legacy_event_phase_key_id_,
965 Variadic::String(phase_id));
966 });
967 // Step events don't support thread timestamps, so no need to add a row to
968 // virtual_track_slices.
969 return base::OkStatus();
970 }
971
ParseAsyncInstantEvent()972 base::Status ParseAsyncInstantEvent() {
973 // Handle instant events as slices with zero duration, so that they end
974 // up nested underneath their parent slices.
975 int64_t duration_ns = 0;
976 int64_t tidelta = 0;
977 auto opt_slice_id = context_->slice_tracker->Scoped(
978 ts_, track_id_, category_id_, name_id_, duration_ns,
979 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
980 if (!opt_slice_id.has_value()) {
981 return base::OkStatus();
982 }
983 MaybeParseFlowEvents(opt_slice_id.value());
984 if (legacy_event_.use_async_tts()) {
985 auto* vtrack_slices = storage_->mutable_virtual_track_slices();
986 PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
987 vtrack_slices->slice_ids().back() < opt_slice_id.value());
988 int64_t tts = thread_timestamp_.value_or(0);
989 int64_t tic = thread_instruction_count_.value_or(0);
990 vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
991 duration_ns, tic, tidelta);
992 }
993 return base::OkStatus();
994 }
995
ParseMetadataEvent()996 base::Status ParseMetadataEvent() {
997 ProcessTracker* procs = context_->process_tracker.get();
998
999 if (name_id_ == kNullStringId)
1000 return base::ErrStatus("Metadata event without name");
1001
1002 // Parse process and thread names from correspondingly named events.
1003 NullTermStringView event_name = storage_->GetString(name_id_);
1004 PERFETTO_DCHECK(event_name.data());
1005 if (event_name == "thread_name") {
1006 if (!utid_) {
1007 return base::ErrStatus(
1008 "thread_name metadata event without thread association");
1009 }
1010
1011 auto it = event_.debug_annotations();
1012 if (!it) {
1013 return base::ErrStatus(
1014 "thread_name metadata event without debug annotations");
1015 }
1016 protos::pbzero::DebugAnnotation::Decoder annotation(*it);
1017 auto thread_name = annotation.string_value();
1018 if (!thread_name.size)
1019 return base::OkStatus();
1020 auto thread_name_id = storage_->InternString(thread_name);
1021 procs->UpdateThreadNameByUtid(
1022 *utid_, thread_name_id,
1023 ThreadNamePriority::kTrackDescriptorThreadType);
1024 return base::OkStatus();
1025 }
1026 if (event_name == "process_name") {
1027 if (!upid_) {
1028 return base::ErrStatus(
1029 "process_name metadata event without process association");
1030 }
1031
1032 auto it = event_.debug_annotations();
1033 if (!it) {
1034 return base::ErrStatus(
1035 "process_name metadata event without debug annotations");
1036 }
1037 protos::pbzero::DebugAnnotation::Decoder annotation(*it);
1038 auto process_name = annotation.string_value();
1039 if (!process_name.size)
1040 return base::OkStatus();
1041 auto process_name_id =
1042 storage_->InternString(base::StringView(process_name));
1043 // Don't override system-provided names.
1044 procs->SetProcessNameIfUnset(*upid_, process_name_id);
1045 return base::OkStatus();
1046 }
1047 // Other metadata events are proxied via the raw table for JSON export.
1048 ParseLegacyEventAsRawEvent();
1049 return base::OkStatus();
1050 }
1051
ParseLegacyEventAsRawEvent()1052 base::Status ParseLegacyEventAsRawEvent() {
1053 if (!utid_)
1054 return base::ErrStatus("raw legacy event without thread association");
1055
1056 auto ucpu = context_->cpu_tracker->GetOrCreateCpu(0);
1057 RawId id =
1058 storage_->mutable_raw_table()
1059 ->Insert({ts_, parser_->raw_legacy_event_id_, *utid_, 0, 0, ucpu})
1060 .id;
1061
1062 auto inserter = context_->args_tracker->AddArgsTo(id);
1063 inserter
1064 .AddArg(parser_->legacy_event_category_key_id_,
1065 Variadic::String(category_id_))
1066 .AddArg(parser_->legacy_event_name_key_id_, Variadic::String(name_id_));
1067
1068 std::string phase_string(1, static_cast<char>(legacy_event_.phase()));
1069 StringId phase_id = storage_->InternString(phase_string.c_str());
1070 inserter.AddArg(parser_->legacy_event_phase_key_id_,
1071 Variadic::String(phase_id));
1072
1073 if (legacy_event_.has_duration_us()) {
1074 inserter.AddArg(parser_->legacy_event_duration_ns_key_id_,
1075 Variadic::Integer(legacy_event_.duration_us() * 1000));
1076 }
1077
1078 if (thread_timestamp_) {
1079 inserter.AddArg(parser_->legacy_event_thread_timestamp_ns_key_id_,
1080 Variadic::Integer(*thread_timestamp_));
1081 if (legacy_event_.has_thread_duration_us()) {
1082 inserter.AddArg(
1083 parser_->legacy_event_thread_duration_ns_key_id_,
1084 Variadic::Integer(legacy_event_.thread_duration_us() * 1000));
1085 }
1086 }
1087
1088 if (thread_instruction_count_) {
1089 inserter.AddArg(parser_->legacy_event_thread_instruction_count_key_id_,
1090 Variadic::Integer(*thread_instruction_count_));
1091 if (legacy_event_.has_thread_instruction_delta()) {
1092 inserter.AddArg(
1093 parser_->legacy_event_thread_instruction_delta_key_id_,
1094 Variadic::Integer(legacy_event_.thread_instruction_delta()));
1095 }
1096 }
1097
1098 if (legacy_event_.use_async_tts()) {
1099 inserter.AddArg(parser_->legacy_event_use_async_tts_key_id_,
1100 Variadic::Boolean(true));
1101 }
1102
1103 bool has_id = false;
1104 if (legacy_event_.has_unscoped_id()) {
1105 // Unscoped ids are either global or local depending on the phase. Pass
1106 // them through as unscoped IDs to JSON export to preserve this behavior.
1107 inserter.AddArg(parser_->legacy_event_unscoped_id_key_id_,
1108 Variadic::UnsignedInteger(legacy_event_.unscoped_id()));
1109 has_id = true;
1110 } else if (legacy_event_.has_global_id()) {
1111 inserter.AddArg(parser_->legacy_event_global_id_key_id_,
1112 Variadic::UnsignedInteger(legacy_event_.global_id()));
1113 has_id = true;
1114 } else if (legacy_event_.has_local_id()) {
1115 inserter.AddArg(parser_->legacy_event_local_id_key_id_,
1116 Variadic::UnsignedInteger(legacy_event_.local_id()));
1117 has_id = true;
1118 }
1119
1120 if (has_id && legacy_event_.has_id_scope() &&
1121 legacy_event_.id_scope().size) {
1122 inserter.AddArg(
1123 parser_->legacy_event_id_scope_key_id_,
1124 Variadic::String(storage_->InternString(legacy_event_.id_scope())));
1125 }
1126
1127 // No need to parse legacy_event.instant_event_scope() because we import
1128 // instant events into the slice table.
1129
1130 ParseTrackEventArgs(&inserter);
1131 return base::OkStatus();
1132 }
1133
ParseTrackEventArgs(BoundInserter * inserter)1134 void ParseTrackEventArgs(BoundInserter* inserter) {
1135 auto log_errors = [this](const base::Status& status) {
1136 if (status.ok())
1137 return;
1138 // Log error but continue parsing the other args.
1139 storage_->IncrementStats(stats::track_event_parser_errors);
1140 PERFETTO_DLOG("ParseTrackEventArgs error: %s", status.c_message());
1141 };
1142
1143 if (event_.has_source_location_iid()) {
1144 log_errors(AddSourceLocationArgs(event_.source_location_iid(), inserter));
1145 }
1146
1147 if (event_.has_task_execution()) {
1148 log_errors(ParseTaskExecutionArgs(event_.task_execution(), inserter));
1149 }
1150 if (event_.has_log_message()) {
1151 log_errors(ParseLogMessage(event_.log_message(), inserter));
1152 }
1153 if (event_.has_chrome_histogram_sample()) {
1154 log_errors(
1155 ParseHistogramName(event_.chrome_histogram_sample(), inserter));
1156 }
1157 if (event_.has_chrome_active_processes()) {
1158 protos::pbzero::ChromeActiveProcesses::Decoder message(
1159 event_.chrome_active_processes());
1160 for (auto it = message.pid(); it; ++it) {
1161 parser_->AddActiveProcess(ts_, *it);
1162 }
1163 }
1164
1165 ArgsParser args_writer(ts_, *inserter, *storage_, sequence_state_,
1166 /*support_json=*/true);
1167 int unknown_extensions = 0;
1168 log_errors(parser_->args_parser_.ParseMessage(
1169 blob_, ".perfetto.protos.TrackEvent", &parser_->reflect_fields_,
1170 args_writer, &unknown_extensions));
1171 if (unknown_extensions > 0) {
1172 context_->storage->IncrementStats(stats::unknown_extension_fields,
1173 unknown_extensions);
1174 }
1175
1176 {
1177 auto key = parser_->args_parser_.EnterDictionary("debug");
1178 util::DebugAnnotationParser parser(parser_->args_parser_);
1179 for (auto it = event_.debug_annotations(); it; ++it) {
1180 log_errors(parser.Parse(*it, args_writer));
1181 }
1182 }
1183
1184 if (legacy_passthrough_utid_) {
1185 inserter->AddArg(parser_->legacy_event_passthrough_utid_id_,
1186 Variadic::UnsignedInteger(*legacy_passthrough_utid_),
1187 ArgsTracker::UpdatePolicy::kSkipIfExists);
1188 }
1189 }
1190
ParseTaskExecutionArgs(ConstBytes task_execution,BoundInserter * inserter)1191 base::Status ParseTaskExecutionArgs(ConstBytes task_execution,
1192 BoundInserter* inserter) {
1193 protos::pbzero::TaskExecution::Decoder task(task_execution);
1194 uint64_t iid = task.posted_from_iid();
1195 if (!iid)
1196 return base::ErrStatus("TaskExecution with invalid posted_from_iid");
1197
1198 auto* decoder = sequence_state_->LookupInternedMessage<
1199 protos::pbzero::InternedData::kSourceLocationsFieldNumber,
1200 protos::pbzero::SourceLocation>(iid);
1201 if (!decoder)
1202 return base::ErrStatus("TaskExecution with invalid posted_from_iid");
1203
1204 StringId file_name_id = kNullStringId;
1205 StringId function_name_id = kNullStringId;
1206 uint32_t line_number = 0;
1207
1208 std::string file_name = NormalizePathSeparators(decoder->file_name());
1209 file_name_id = storage_->InternString(base::StringView(file_name));
1210 function_name_id = storage_->InternString(decoder->function_name());
1211 line_number = decoder->line_number();
1212
1213 inserter->AddArg(parser_->task_file_name_args_key_id_,
1214 Variadic::String(file_name_id));
1215 inserter->AddArg(parser_->task_function_name_args_key_id_,
1216 Variadic::String(function_name_id));
1217 inserter->AddArg(parser_->task_line_number_args_key_id_,
1218 Variadic::UnsignedInteger(line_number));
1219 return base::OkStatus();
1220 }
1221
AddSourceLocationArgs(uint64_t iid,BoundInserter * inserter)1222 base::Status AddSourceLocationArgs(uint64_t iid, BoundInserter* inserter) {
1223 if (!iid)
1224 return base::ErrStatus("SourceLocation with invalid iid");
1225
1226 auto* decoder = sequence_state_->LookupInternedMessage<
1227 protos::pbzero::InternedData::kSourceLocationsFieldNumber,
1228 protos::pbzero::SourceLocation>(iid);
1229 if (!decoder)
1230 return base::ErrStatus("SourceLocation with invalid iid");
1231
1232 StringId file_name_id = kNullStringId;
1233 StringId function_name_id = kNullStringId;
1234 uint32_t line_number = 0;
1235
1236 std::string file_name = NormalizePathSeparators(decoder->file_name());
1237 file_name_id = storage_->InternString(base::StringView(file_name));
1238 function_name_id = storage_->InternString(decoder->function_name());
1239 line_number = decoder->line_number();
1240
1241 inserter->AddArg(parser_->source_location_file_name_key_id_,
1242 Variadic::String(file_name_id));
1243 inserter->AddArg(parser_->source_location_function_name_key_id_,
1244 Variadic::String(function_name_id));
1245 inserter->AddArg(parser_->source_location_line_number_key_id_,
1246 Variadic::UnsignedInteger(line_number));
1247 return base::OkStatus();
1248 }
1249
ParseLogMessage(ConstBytes blob,BoundInserter * inserter)1250 base::Status ParseLogMessage(ConstBytes blob, BoundInserter* inserter) {
1251 if (!utid_)
1252 return base::ErrStatus("LogMessage without thread association");
1253
1254 protos::pbzero::LogMessage::Decoder message(blob);
1255
1256 auto* body_decoder = sequence_state_->LookupInternedMessage<
1257 protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
1258 protos::pbzero::LogMessageBody>(message.body_iid());
1259 if (!body_decoder)
1260 return base::ErrStatus("LogMessage with invalid body_iid");
1261
1262 const StringId log_message_id =
1263 storage_->InternString(body_decoder->body());
1264 inserter->AddArg(parser_->log_message_body_key_id_,
1265 Variadic::String(log_message_id));
1266
1267 StringId source_location_id = kNullStringId;
1268 if (message.has_source_location_iid()) {
1269 auto* source_location_decoder = sequence_state_->LookupInternedMessage<
1270 protos::pbzero::InternedData::kSourceLocationsFieldNumber,
1271 protos::pbzero::SourceLocation>(message.source_location_iid());
1272 if (!source_location_decoder)
1273 return base::ErrStatus("LogMessage with invalid source_location_iid");
1274 const std::string source_location =
1275 source_location_decoder->file_name().ToStdString() + ":" +
1276 std::to_string(source_location_decoder->line_number());
1277 source_location_id =
1278 storage_->InternString(base::StringView(source_location));
1279
1280 inserter->AddArg(parser_->log_message_source_location_file_name_key_id_,
1281 Variadic::String(storage_->InternString(
1282 source_location_decoder->file_name())));
1283 inserter->AddArg(
1284 parser_->log_message_source_location_function_name_key_id_,
1285 Variadic::String(storage_->InternString(
1286 source_location_decoder->function_name())));
1287 inserter->AddArg(
1288 parser_->log_message_source_location_line_number_key_id_,
1289 Variadic::Integer(source_location_decoder->line_number()));
1290 }
1291
1292 // The track event log message doesn't specify any priority. UI never
1293 // displays priorities < 2 (VERBOSE in android). Let's make all the track
1294 // event logs show up as INFO.
1295 int32_t priority = protos::pbzero::AndroidLogPriority::PRIO_INFO;
1296 if (message.has_prio()) {
1297 priority = ToAndroidLogPriority(
1298 static_cast<protos::pbzero::LogMessage::Priority>(message.prio()));
1299 inserter->AddArg(parser_->log_message_priority_id_,
1300 Variadic::Integer(priority));
1301 }
1302
1303 storage_->mutable_android_log_table()->Insert(
1304 {ts_, *utid_,
1305 /*priority*/ static_cast<uint32_t>(priority),
1306 /*tag_id*/ source_location_id, log_message_id});
1307
1308 return base::OkStatus();
1309 }
1310
ParseHistogramName(ConstBytes blob,BoundInserter * inserter)1311 base::Status ParseHistogramName(ConstBytes blob, BoundInserter* inserter) {
1312 protos::pbzero::ChromeHistogramSample::Decoder sample(blob);
1313 if (!sample.has_name_iid())
1314 return base::OkStatus();
1315
1316 if (sample.has_name()) {
1317 return base::ErrStatus(
1318 "name is already set for ChromeHistogramSample: only one of name and "
1319 "name_iid can be set.");
1320 }
1321
1322 auto* decoder = sequence_state_->LookupInternedMessage<
1323 protos::pbzero::InternedData::kHistogramNamesFieldNumber,
1324 protos::pbzero::HistogramName>(sample.name_iid());
1325 if (!decoder)
1326 return base::ErrStatus("HistogramName with invalid name_iid");
1327
1328 inserter->AddArg(parser_->histogram_name_key_id_,
1329 Variadic::String(storage_->InternString(decoder->name())));
1330 return base::OkStatus();
1331 }
1332
MakeThreadSliceRow()1333 tables::SliceTable::Row MakeThreadSliceRow() {
1334 tables::SliceTable::Row row;
1335 row.ts = ts_;
1336 row.track_id = track_id_;
1337 row.category = category_id_;
1338 row.name = name_id_;
1339 row.thread_ts = thread_timestamp_;
1340 row.thread_dur = std::nullopt;
1341 row.thread_instruction_count = thread_instruction_count_;
1342 row.thread_instruction_delta = std::nullopt;
1343 return row;
1344 }
1345
1346 TraceProcessorContext* context_;
1347 TrackEventTracker* track_event_tracker_;
1348 TraceStorage* storage_;
1349 TrackEventParser* parser_;
1350 ArgsTranslationTable* args_translation_table_;
1351 int64_t ts_;
1352 const TrackEventData* event_data_;
1353 PacketSequenceStateGeneration* sequence_state_;
1354 ConstBytes blob_;
1355 TrackEvent::Decoder event_;
1356 LegacyEvent::Decoder legacy_event_;
1357 protos::pbzero::TrackEventDefaults::Decoder* defaults_;
1358
1359 // Importing state.
1360 StringId category_id_;
1361 StringId name_id_;
1362 uint64_t track_uuid_;
1363 TrackId track_id_;
1364 std::optional<UniqueTid> utid_;
1365 std::optional<UniqueTid> upid_;
1366 std::optional<int64_t> thread_timestamp_;
1367 std::optional<int64_t> thread_instruction_count_;
1368
1369 // All events in legacy JSON require a thread ID, but for some types of
1370 // events (e.g. async events or process/global-scoped instants), we don't
1371 // store it in the slice/track model. To pass the utid through to the json
1372 // export, we store it in an arg.
1373 std::optional<UniqueTid> legacy_passthrough_utid_;
1374
1375 uint32_t packet_sequence_id_;
1376 };
1377
TrackEventParser(TraceProcessorContext * context,TrackEventTracker * track_event_tracker)1378 TrackEventParser::TrackEventParser(TraceProcessorContext* context,
1379 TrackEventTracker* track_event_tracker)
1380 : args_parser_(*context->descriptor_pool_),
1381 context_(context),
1382 track_event_tracker_(track_event_tracker),
1383 counter_name_thread_time_id_(
1384 context->storage->InternString("thread_time")),
1385 counter_name_thread_instruction_count_id_(
1386 context->storage->InternString("thread_instruction_count")),
1387 task_file_name_args_key_id_(
1388 context->storage->InternString("task.posted_from.file_name")),
1389 task_function_name_args_key_id_(
1390 context->storage->InternString("task.posted_from.function_name")),
1391 task_line_number_args_key_id_(
1392 context->storage->InternString("task.posted_from.line_number")),
1393 log_message_body_key_id_(
1394 context->storage->InternString("track_event.log_message")),
1395 log_message_source_location_function_name_key_id_(
1396 context->storage->InternString(
1397 "track_event.log_message.function_name")),
1398 log_message_source_location_file_name_key_id_(
1399 context->storage->InternString("track_event.log_message.file_name")),
1400 log_message_source_location_line_number_key_id_(
1401 context->storage->InternString(
1402 "track_event.log_message.line_number")),
1403 log_message_priority_id_(
1404 context->storage->InternString("track_event.priority")),
1405 source_location_function_name_key_id_(
1406 context->storage->InternString("source.function_name")),
1407 source_location_file_name_key_id_(
1408 context->storage->InternString("source.file_name")),
1409 source_location_line_number_key_id_(
1410 context->storage->InternString("source.line_number")),
1411 raw_legacy_event_id_(
1412 context->storage->InternString("track_event.legacy_event")),
1413 legacy_event_passthrough_utid_id_(
1414 context->storage->InternString("legacy_event.passthrough_utid")),
1415 legacy_event_category_key_id_(
1416 context->storage->InternString("legacy_event.category")),
1417 legacy_event_name_key_id_(
1418 context->storage->InternString("legacy_event.name")),
1419 legacy_event_phase_key_id_(
1420 context->storage->InternString("legacy_event.phase")),
1421 legacy_event_duration_ns_key_id_(
1422 context->storage->InternString("legacy_event.duration_ns")),
1423 legacy_event_thread_timestamp_ns_key_id_(
1424 context->storage->InternString("legacy_event.thread_timestamp_ns")),
1425 legacy_event_thread_duration_ns_key_id_(
1426 context->storage->InternString("legacy_event.thread_duration_ns")),
1427 legacy_event_thread_instruction_count_key_id_(
1428 context->storage->InternString(
1429 "legacy_event.thread_instruction_count")),
1430 legacy_event_thread_instruction_delta_key_id_(
1431 context->storage->InternString(
1432 "legacy_event.thread_instruction_delta")),
1433 legacy_event_use_async_tts_key_id_(
1434 context->storage->InternString("legacy_event.use_async_tts")),
1435 legacy_event_unscoped_id_key_id_(
1436 context->storage->InternString("legacy_event.unscoped_id")),
1437 legacy_event_global_id_key_id_(
1438 context->storage->InternString("legacy_event.global_id")),
1439 legacy_event_local_id_key_id_(
1440 context->storage->InternString("legacy_event.local_id")),
1441 legacy_event_id_scope_key_id_(
1442 context->storage->InternString("legacy_event.id_scope")),
1443 legacy_event_bind_id_key_id_(
1444 context->storage->InternString("legacy_event.bind_id")),
1445 legacy_event_bind_to_enclosing_key_id_(
1446 context->storage->InternString("legacy_event.bind_to_enclosing")),
1447 legacy_event_flow_direction_key_id_(
1448 context->storage->InternString("legacy_event.flow_direction")),
1449 histogram_name_key_id_(
1450 context->storage->InternString("chrome_histogram_sample.name")),
1451 flow_direction_value_in_id_(context->storage->InternString("in")),
1452 flow_direction_value_out_id_(context->storage->InternString("out")),
1453 flow_direction_value_inout_id_(context->storage->InternString("inout")),
1454 chrome_legacy_ipc_class_args_key_id_(
1455 context->storage->InternString("legacy_ipc.class")),
1456 chrome_legacy_ipc_line_args_key_id_(
1457 context->storage->InternString("legacy_ipc.line")),
1458 chrome_host_app_package_name_id_(
1459 context->storage->InternString("chrome.host_app_package_name")),
1460 chrome_crash_trace_id_name_id_(
1461 context->storage->InternString("chrome.crash_trace_id")),
1462 chrome_process_label_flat_key_id_(
1463 context->storage->InternString("chrome.process_label")),
1464 chrome_process_type_id_(
1465 context_->storage->InternString("chrome.process_type")),
1466 event_category_key_id_(context_->storage->InternString("event.category")),
1467 event_name_key_id_(context_->storage->InternString("event.name")),
1468 chrome_string_lookup_(context->storage.get()),
1469 active_chrome_processes_tracker_(context) {
1470 args_parser_.AddParsingOverrideForField(
1471 "chrome_mojo_event_info.mojo_interface_method_iid",
1472 [](const protozero::Field& field,
1473 util::ProtoToArgsParser::Delegate& delegate) {
1474 return MaybeParseUnsymbolizedSourceLocation(
1475 "chrome_mojo_event_info.mojo_interface_method.native_symbol", field,
1476 delegate);
1477 });
1478 // Switch |source_location_iid| into its interned data variant.
1479 args_parser_.AddParsingOverrideForField(
1480 "begin_impl_frame_args.current_args.source_location_iid",
1481 [](const protozero::Field& field,
1482 util::ProtoToArgsParser::Delegate& delegate) {
1483 return MaybeParseSourceLocation("begin_impl_frame_args.current_args",
1484 field, delegate);
1485 });
1486 args_parser_.AddParsingOverrideForField(
1487 "begin_impl_frame_args.last_args.source_location_iid",
1488 [](const protozero::Field& field,
1489 util::ProtoToArgsParser::Delegate& delegate) {
1490 return MaybeParseSourceLocation("begin_impl_frame_args.last_args",
1491 field, delegate);
1492 });
1493 args_parser_.AddParsingOverrideForField(
1494 "begin_frame_observer_state.last_begin_frame_args.source_location_iid",
1495 [](const protozero::Field& field,
1496 util::ProtoToArgsParser::Delegate& delegate) {
1497 return MaybeParseSourceLocation(
1498 "begin_frame_observer_state.last_begin_frame_args", field,
1499 delegate);
1500 });
1501 args_parser_.AddParsingOverrideForField(
1502 "chrome_memory_pressure_notification.creation_location_iid",
1503 [](const protozero::Field& field,
1504 util::ProtoToArgsParser::Delegate& delegate) {
1505 return MaybeParseSourceLocation("chrome_memory_pressure_notification",
1506 field, delegate);
1507 });
1508
1509 // Parse DebugAnnotations.
1510 args_parser_.AddParsingOverrideForType(
1511 ".perfetto.protos.DebugAnnotation",
1512 [&](util::ProtoToArgsParser::ScopedNestedKeyContext& key,
1513 const protozero::ConstBytes& data,
1514 util::ProtoToArgsParser::Delegate& delegate) {
1515 // Do not add "debug_annotations" to the final key.
1516 key.RemoveFieldSuffix();
1517 util::DebugAnnotationParser annotation_parser(args_parser_);
1518 return annotation_parser.Parse(data, delegate);
1519 });
1520
1521 args_parser_.AddParsingOverrideForField(
1522 "active_processes.pid", [&](const protozero::Field& field,
1523 util::ProtoToArgsParser::Delegate& delegate) {
1524 AddActiveProcess(delegate.packet_timestamp(), field.as_int32());
1525 // Fallthrough so that the parser adds pid as a regular arg.
1526 return std::nullopt;
1527 });
1528
1529 for (uint16_t index : kReflectFields) {
1530 reflect_fields_.push_back(index);
1531 }
1532 }
1533
ParseTrackDescriptor(int64_t packet_timestamp,protozero::ConstBytes track_descriptor,uint32_t packet_sequence_id)1534 void TrackEventParser::ParseTrackDescriptor(
1535 int64_t packet_timestamp,
1536 protozero::ConstBytes track_descriptor,
1537 uint32_t packet_sequence_id) {
1538 protos::pbzero::TrackDescriptor::Decoder decoder(track_descriptor);
1539
1540 // Ensure that the track and its parents are resolved. This may start a new
1541 // process and/or thread (i.e. new upid/utid).
1542 TrackId track_id = *track_event_tracker_->GetDescriptorTrack(
1543 decoder.uuid(), kNullStringId, packet_sequence_id);
1544
1545 if (decoder.has_thread()) {
1546 UniqueTid utid = ParseThreadDescriptor(decoder.thread());
1547 if (decoder.has_chrome_thread())
1548 ParseChromeThreadDescriptor(utid, decoder.chrome_thread());
1549 } else if (decoder.has_process()) {
1550 UniquePid upid =
1551 ParseProcessDescriptor(packet_timestamp, decoder.process());
1552 if (decoder.has_chrome_process())
1553 ParseChromeProcessDescriptor(upid, decoder.chrome_process());
1554 }
1555
1556 // Override the name with the most recent name seen (after sorting by ts).
1557 ::protozero::ConstChars name = {nullptr, 0};
1558 if (decoder.has_name()) {
1559 name = decoder.name();
1560 } else if (decoder.has_static_name()) {
1561 name = decoder.static_name();
1562 } else if (decoder.has_atrace_name()) {
1563 name = decoder.atrace_name();
1564 }
1565 if (name.data != nullptr) {
1566 auto* tracks = context_->storage->mutable_track_table();
1567 const StringId raw_name_id = context_->storage->InternString(name);
1568 const StringId name_id =
1569 context_->process_track_translation_table->TranslateName(raw_name_id);
1570 tracks->FindById(track_id)->set_name(name_id);
1571 }
1572 }
1573
ParseProcessDescriptor(int64_t packet_timestamp,protozero::ConstBytes process_descriptor)1574 UniquePid TrackEventParser::ParseProcessDescriptor(
1575 int64_t packet_timestamp,
1576 protozero::ConstBytes process_descriptor) {
1577 protos::pbzero::ProcessDescriptor::Decoder decoder(process_descriptor);
1578 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
1579 static_cast<uint32_t>(decoder.pid()));
1580 active_chrome_processes_tracker_.AddProcessDescriptor(packet_timestamp, upid);
1581 if (decoder.has_process_name() && decoder.process_name().size) {
1582 // Don't override system-provided names.
1583 context_->process_tracker->SetProcessNameIfUnset(
1584 upid, context_->storage->InternString(decoder.process_name()));
1585 }
1586 if (decoder.has_start_timestamp_ns() && decoder.start_timestamp_ns() > 0) {
1587 context_->process_tracker->SetStartTsIfUnset(upid,
1588 decoder.start_timestamp_ns());
1589 }
1590 // TODO(skyostil): Remove parsing for legacy chrome_process_type field.
1591 if (decoder.has_chrome_process_type()) {
1592 StringId name_id =
1593 chrome_string_lookup_.GetProcessName(decoder.chrome_process_type());
1594 // Don't override system-provided names.
1595 context_->process_tracker->SetProcessNameIfUnset(upid, name_id);
1596 }
1597 int label_index = 0;
1598 for (auto it = decoder.process_labels(); it; it++) {
1599 StringId label_id = context_->storage->InternString(*it);
1600 std::string key = "chrome.process_label[";
1601 key.append(std::to_string(label_index++));
1602 key.append("]");
1603 context_->process_tracker->AddArgsTo(upid).AddArg(
1604 chrome_process_label_flat_key_id_,
1605 context_->storage->InternString(base::StringView(key)),
1606 Variadic::String(label_id));
1607 }
1608 return upid;
1609 }
1610
ParseChromeProcessDescriptor(UniquePid upid,protozero::ConstBytes chrome_process_descriptor)1611 void TrackEventParser::ParseChromeProcessDescriptor(
1612 UniquePid upid,
1613 protozero::ConstBytes chrome_process_descriptor) {
1614 protos::pbzero::ChromeProcessDescriptor::Decoder decoder(
1615 chrome_process_descriptor);
1616
1617 StringId name_id =
1618 chrome_string_lookup_.GetProcessName(decoder.process_type());
1619 // Don't override system-provided names.
1620 context_->process_tracker->SetProcessNameIfUnset(upid, name_id);
1621
1622 ArgsTracker::BoundInserter process_args =
1623 context_->process_tracker->AddArgsTo(upid);
1624 // For identifying Chrome processes in system traces.
1625 process_args.AddArg(chrome_process_type_id_, Variadic::String(name_id));
1626 if (decoder.has_host_app_package_name()) {
1627 process_args.AddArg(chrome_host_app_package_name_id_,
1628 Variadic::String(context_->storage->InternString(
1629 decoder.host_app_package_name())));
1630 }
1631 if (decoder.has_crash_trace_id()) {
1632 process_args.AddArg(chrome_crash_trace_id_name_id_,
1633 Variadic::UnsignedInteger(decoder.crash_trace_id()));
1634 }
1635 }
1636
ParseThreadDescriptor(protozero::ConstBytes thread_descriptor)1637 UniqueTid TrackEventParser::ParseThreadDescriptor(
1638 protozero::ConstBytes thread_descriptor) {
1639 protos::pbzero::ThreadDescriptor::Decoder decoder(thread_descriptor);
1640 UniqueTid utid = context_->process_tracker->UpdateThread(
1641 static_cast<uint32_t>(decoder.tid()),
1642 static_cast<uint32_t>(decoder.pid()));
1643 StringId name_id = kNullStringId;
1644 if (decoder.has_thread_name() && decoder.thread_name().size) {
1645 name_id = context_->storage->InternString(decoder.thread_name());
1646 } else if (decoder.has_chrome_thread_type()) {
1647 // TODO(skyostil): Remove parsing for legacy chrome_thread_type field.
1648 name_id = chrome_string_lookup_.GetThreadName(decoder.chrome_thread_type());
1649 }
1650 context_->process_tracker->UpdateThreadNameByUtid(
1651 utid, name_id, ThreadNamePriority::kTrackDescriptor);
1652 return utid;
1653 }
1654
ParseChromeThreadDescriptor(UniqueTid utid,protozero::ConstBytes chrome_thread_descriptor)1655 void TrackEventParser::ParseChromeThreadDescriptor(
1656 UniqueTid utid,
1657 protozero::ConstBytes chrome_thread_descriptor) {
1658 protos::pbzero::ChromeThreadDescriptor::Decoder decoder(
1659 chrome_thread_descriptor);
1660 if (!decoder.has_thread_type())
1661 return;
1662
1663 StringId name_id = chrome_string_lookup_.GetThreadName(decoder.thread_type());
1664 context_->process_tracker->UpdateThreadNameByUtid(
1665 utid, name_id, ThreadNamePriority::kTrackDescriptorThreadType);
1666 }
1667
ParseTrackEvent(int64_t ts,const TrackEventData * event_data,ConstBytes blob,uint32_t packet_sequence_id)1668 void TrackEventParser::ParseTrackEvent(int64_t ts,
1669 const TrackEventData* event_data,
1670 ConstBytes blob,
1671 uint32_t packet_sequence_id) {
1672 const auto range_of_interest_start_us =
1673 track_event_tracker_->range_of_interest_start_us();
1674 if (context_->config.drop_track_event_data_before ==
1675 DropTrackEventDataBefore::kTrackEventRangeOfInterest &&
1676 range_of_interest_start_us && ts < *range_of_interest_start_us * 1000) {
1677 // The event is outside of the range of interest, and dropping is enabled.
1678 // So we drop the event.
1679 context_->storage->IncrementStats(
1680 stats::track_event_dropped_packets_outside_of_range_of_interest);
1681 return;
1682 }
1683 base::Status status =
1684 EventImporter(this, ts, event_data, blob, packet_sequence_id).Import();
1685 if (!status.ok()) {
1686 context_->storage->IncrementStats(stats::track_event_parser_errors);
1687 PERFETTO_DLOG("ParseTrackEvent error: %s", status.c_message());
1688 }
1689 }
1690
AddActiveProcess(int64_t packet_timestamp,int32_t pid)1691 void TrackEventParser::AddActiveProcess(int64_t packet_timestamp, int32_t pid) {
1692 UniquePid upid =
1693 context_->process_tracker->GetOrCreateProcess(static_cast<uint32_t>(pid));
1694 active_chrome_processes_tracker_.AddActiveProcessMetadata(packet_timestamp,
1695 upid);
1696 }
1697
NotifyEndOfFile()1698 void TrackEventParser::NotifyEndOfFile() {
1699 active_chrome_processes_tracker_.NotifyEndOfFile();
1700 }
1701
1702 } // namespace perfetto::trace_processor
1703