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