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