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