xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/track_event_parser.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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