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