1 /*
2  * Copyright (C) 2018 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/proto_trace_parser.h"
18 
19 #include <inttypes.h>
20 #include <string.h>
21 
22 #include <string>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/base/optional.h"
26 #include "perfetto/base/string_view.h"
27 #include "perfetto/base/utils.h"
28 #include "perfetto/protozero/proto_decoder.h"
29 #include "perfetto/traced/sys_stats_counters.h"
30 #include "src/trace_processor/args_tracker.h"
31 #include "src/trace_processor/clock_tracker.h"
32 #include "src/trace_processor/event_tracker.h"
33 #include "src/trace_processor/ftrace_descriptors.h"
34 #include "src/trace_processor/heap_profile_tracker.h"
35 #include "src/trace_processor/process_tracker.h"
36 #include "src/trace_processor/slice_tracker.h"
37 #include "src/trace_processor/syscall_tracker.h"
38 #include "src/trace_processor/trace_processor_context.h"
39 
40 #include "perfetto/common/android_log_constants.pbzero.h"
41 #include "perfetto/common/trace_stats.pbzero.h"
42 #include "perfetto/trace/android/android_log.pbzero.h"
43 #include "perfetto/trace/clock_snapshot.pbzero.h"
44 #include "perfetto/trace/ftrace/ftrace.pbzero.h"
45 #include "perfetto/trace/ftrace/ftrace_event.pbzero.h"
46 #include "perfetto/trace/ftrace/ftrace_stats.pbzero.h"
47 #include "perfetto/trace/ftrace/generic.pbzero.h"
48 #include "perfetto/trace/ftrace/kmem.pbzero.h"
49 #include "perfetto/trace/ftrace/lowmemorykiller.pbzero.h"
50 #include "perfetto/trace/ftrace/mm_event.pbzero.h"
51 #include "perfetto/trace/ftrace/oom.pbzero.h"
52 #include "perfetto/trace/ftrace/power.pbzero.h"
53 #include "perfetto/trace/ftrace/raw_syscalls.pbzero.h"
54 #include "perfetto/trace/ftrace/sched.pbzero.h"
55 #include "perfetto/trace/ftrace/signal.pbzero.h"
56 #include "perfetto/trace/ftrace/task.pbzero.h"
57 #include "perfetto/trace/interned_data/interned_data.pbzero.h"
58 #include "perfetto/trace/power/battery_counters.pbzero.h"
59 #include "perfetto/trace/power/power_rails.pbzero.h"
60 #include "perfetto/trace/profiling/profile_packet.pbzero.h"
61 #include "perfetto/trace/ps/process_stats.pbzero.h"
62 #include "perfetto/trace/ps/process_tree.pbzero.h"
63 #include "perfetto/trace/sys_stats/sys_stats.pbzero.h"
64 #include "perfetto/trace/system_info.pbzero.h"
65 #include "perfetto/trace/trace.pbzero.h"
66 #include "perfetto/trace/trace_packet.pbzero.h"
67 #include "perfetto/trace/track_event/debug_annotation.pbzero.h"
68 #include "perfetto/trace/track_event/task_execution.pbzero.h"
69 #include "perfetto/trace/track_event/track_event.pbzero.h"
70 
71 namespace perfetto {
72 namespace trace_processor {
73 
74 namespace {
75 
76 using protozero::ProtoDecoder;
77 using Variadic = TraceStorage::Args::Variadic;
78 
79 }  // namespace
80 
81 // We have to handle trace_marker events of a few different types:
82 // 1. some random text
83 // 2. B|1636|pokeUserActivity
84 // 3. E|1636
85 // 4. C|1636|wq:monitor|0
ParseSystraceTracePoint(base::StringView str,SystraceTracePoint * out)86 SystraceParseResult ParseSystraceTracePoint(base::StringView str,
87                                             SystraceTracePoint* out) {
88   // THIS char* IS NOT NULL TERMINATED.
89   const char* s = str.data();
90   size_t len = str.size();
91 
92   if (len < 2)
93     return SystraceParseResult::kFailure;
94 
95   // If str matches '[BEC]\|[0-9]+[\|\n]' set tgid_length to the length of
96   // the number. Otherwise return kFailure.
97   if (s[1] != '|' && s[1] != '\n')
98     return SystraceParseResult::kFailure;
99   if (s[0] != 'B' && s[0] != 'E' && s[0] != 'C') {
100     // TODO: support android async slices
101     return s[0] == 'S' || s[0] == 'F' ? SystraceParseResult::kUnsupported
102                                       : SystraceParseResult::kFailure;
103   }
104   size_t tgid_length = 0;
105   for (size_t i = 2; i < len; i++) {
106     if (s[i] == '|' || s[i] == '\n') {
107       tgid_length = i - 2;
108       break;
109     }
110     if (s[i] < '0' || s[i] > '9')
111       return SystraceParseResult::kFailure;
112   }
113 
114   if (tgid_length == 0) {
115     out->tgid = 0;
116   } else {
117     std::string tgid_str(s + 2, tgid_length);
118     out->tgid = static_cast<uint32_t>(std::stoi(tgid_str.c_str()));
119   }
120 
121   out->phase = s[0];
122   switch (s[0]) {
123     case 'B': {
124       size_t name_index = 2 + tgid_length + 1;
125       out->name = base::StringView(
126           s + name_index, len - name_index - (s[len - 1] == '\n' ? 1 : 0));
127       return SystraceParseResult::kSuccess;
128     }
129     case 'E': {
130       return SystraceParseResult::kSuccess;
131     }
132     case 'C': {
133       size_t name_index = 2 + tgid_length + 1;
134       size_t name_length = 0;
135       for (size_t i = name_index; i < len; i++) {
136         if (s[i] == '|' || s[i] == '\n') {
137           name_length = i - name_index;
138           break;
139         }
140       }
141       out->name = base::StringView(s + name_index, name_length);
142 
143       size_t value_index = name_index + name_length + 1;
144       size_t value_len = len - value_index;
145       char value_str[32];
146       if (value_len >= sizeof(value_str)) {
147         return SystraceParseResult::kFailure;
148       }
149       memcpy(value_str, s + value_index, value_len);
150       value_str[value_len] = 0;
151       out->value = std::stod(value_str);
152       return SystraceParseResult::kSuccess;
153     }
154     default:
155       return SystraceParseResult::kFailure;
156   }
157 }
158 
ProtoTraceParser(TraceProcessorContext * context)159 ProtoTraceParser::ProtoTraceParser(TraceProcessorContext* context)
160     : context_(context),
161       utid_name_id_(context->storage->InternString("utid")),
162       sched_wakeup_name_id_(context->storage->InternString("sched_wakeup")),
163       cpu_freq_name_id_(context->storage->InternString("cpufreq")),
164       cpu_idle_name_id_(context->storage->InternString("cpuidle")),
165       comm_name_id_(context->storage->InternString("comm")),
166       num_forks_name_id_(context->storage->InternString("num_forks")),
167       num_irq_total_name_id_(context->storage->InternString("num_irq_total")),
168       num_softirq_total_name_id_(
169           context->storage->InternString("num_softirq_total")),
170       num_irq_name_id_(context->storage->InternString("num_irq")),
171       num_softirq_name_id_(context->storage->InternString("num_softirq")),
172       cpu_times_user_ns_id_(
173           context->storage->InternString("cpu.times.user_ns")),
174       cpu_times_user_nice_ns_id_(
175           context->storage->InternString("cpu.times.user_nice_ns")),
176       cpu_times_system_mode_ns_id_(
177           context->storage->InternString("cpu.times.system_mode_ns")),
178       cpu_times_idle_ns_id_(
179           context->storage->InternString("cpu.times.idle_ns")),
180       cpu_times_io_wait_ns_id_(
181           context->storage->InternString("cpu.times.io_wait_ns")),
182       cpu_times_irq_ns_id_(context->storage->InternString("cpu.times.irq_ns")),
183       cpu_times_softirq_ns_id_(
184           context->storage->InternString("cpu.times.softirq_ns")),
185       signal_deliver_id_(context->storage->InternString("signal_deliver")),
186       signal_generate_id_(context->storage->InternString("signal_generate")),
187       batt_charge_id_(context->storage->InternString("batt.charge_uah")),
188       batt_capacity_id_(context->storage->InternString("batt.capacity_pct")),
189       batt_current_id_(context->storage->InternString("batt.current_ua")),
190       batt_current_avg_id_(
191           context->storage->InternString("batt.current.avg_ua")),
192       lmk_id_(context->storage->InternString("mem.lmk")),
193       oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
194       ion_total_unknown_id_(context->storage->InternString("mem.ion.unknown")),
195       ion_change_unknown_id_(
196           context->storage->InternString("mem.ion_change.unknown")) {
197   for (const auto& name : BuildMeminfoCounterNames()) {
198     meminfo_strs_id_.emplace_back(context->storage->InternString(name));
199   }
200   for (const auto& name : BuildVmstatCounterNames()) {
201     vmstat_strs_id_.emplace_back(context->storage->InternString(name));
202   }
203   rss_members_.emplace_back(context->storage->InternString("mem.rss.file"));
204   rss_members_.emplace_back(context->storage->InternString("mem.rss.anon"));
205   rss_members_.emplace_back(context->storage->InternString("mem.swap"));
206   rss_members_.emplace_back(context->storage->InternString("mem.rss.shmem"));
207   rss_members_.emplace_back(
208       context->storage->InternString("mem.rss.unknown"));  // Keep this last.
209 
210   using ProcessStats = protos::pbzero::ProcessStats;
211   proc_stats_process_names_[ProcessStats::Process::kVmSizeKbFieldNumber] =
212       context->storage->InternString("mem.virt");
213   proc_stats_process_names_[ProcessStats::Process::kVmRssKbFieldNumber] =
214       context->storage->InternString("mem.rss");
215   proc_stats_process_names_[ProcessStats::Process::kRssAnonKbFieldNumber] =
216       context->storage->InternString("mem.rss.anon");
217   proc_stats_process_names_[ProcessStats::Process::kRssFileKbFieldNumber] =
218       context->storage->InternString("mem.rss.file");
219   proc_stats_process_names_[ProcessStats::Process::kRssShmemKbFieldNumber] =
220       context->storage->InternString("mem.rss.shmem");
221   proc_stats_process_names_[ProcessStats::Process::kVmSwapKbFieldNumber] =
222       context->storage->InternString("mem.swap");
223   proc_stats_process_names_[ProcessStats::Process::kVmLockedKbFieldNumber] =
224       context->storage->InternString("mem.locked");
225   proc_stats_process_names_[ProcessStats::Process::kVmHwmKbFieldNumber] =
226       context->storage->InternString("mem.rss.watermark");
227   proc_stats_process_names_[ProcessStats::Process::kOomScoreAdjFieldNumber] =
228       oom_score_adj_id_;
229 
230   mm_event_counter_names_ = {
231       {MmEventCounterNames(
232            context->storage->InternString("mem.mm.min_flt.count"),
233            context->storage->InternString("mem.mm.min_flt.max_lat"),
234            context->storage->InternString("mem.mm.min_flt.avg_lat")),
235        MmEventCounterNames(
236            context->storage->InternString("mem.mm.maj_flt.count"),
237            context->storage->InternString("mem.mm.maj_flt.max_lat"),
238            context->storage->InternString("mem.mm.maj_flt.avg_lat")),
239        MmEventCounterNames(
240            context->storage->InternString("mem.mm.read_io.count"),
241            context->storage->InternString("mem.mm.read_io.max_lat"),
242            context->storage->InternString("mem.mm.read_io.avg_lat")),
243        MmEventCounterNames(
244            context->storage->InternString("mem.mm.compaction.count"),
245            context->storage->InternString("mem.mm.compaction.max_lat"),
246            context->storage->InternString("mem.mm.compaction.avg_lat")),
247        MmEventCounterNames(
248            context->storage->InternString("mem.mm.reclaim.count"),
249            context->storage->InternString("mem.mm.reclaim.max_lat"),
250            context->storage->InternString("mem.mm.reclaim.avg_lat")),
251        MmEventCounterNames(
252            context->storage->InternString("mem.mm.swp_flt.count"),
253            context->storage->InternString("mem.mm.swp_flt.max_lat"),
254            context->storage->InternString("mem.mm.swp_flt.avg_lat")),
255        MmEventCounterNames(
256            context->storage->InternString("mem.mm.kern_alloc.count"),
257            context->storage->InternString("mem.mm.kern_alloc.max_lat"),
258            context->storage->InternString("mem.mm.kern_alloc.avg_lat"))}};
259 
260   // Build the lookup table for the strings inside ftrace events (e.g. the
261   // name of ftrace event fields and the names of their args).
262   for (size_t i = 0; i < GetDescriptorsSize(); i++) {
263     auto* descriptor = GetMessageDescriptorForId(i);
264     if (!descriptor->name) {
265       ftrace_message_strings_.emplace_back();
266       continue;
267     }
268 
269     FtraceMessageStrings ftrace_strings;
270     ftrace_strings.message_name_id =
271         context->storage->InternString(descriptor->name);
272 
273     for (size_t fid = 0; fid <= descriptor->max_field_id; fid++) {
274       const auto& field = descriptor->fields[fid];
275       if (!field.name)
276         continue;
277       ftrace_strings.field_name_ids[fid] =
278           context->storage->InternString(field.name);
279     }
280     ftrace_message_strings_.emplace_back(ftrace_strings);
281   }
282 }
283 
284 ProtoTraceParser::~ProtoTraceParser() = default;
285 
ParseTracePacket(int64_t ts,TraceSorter::TimestampedTracePiece ttp)286 void ProtoTraceParser::ParseTracePacket(
287     int64_t ts,
288     TraceSorter::TimestampedTracePiece ttp) {
289   PERFETTO_DCHECK(ttp.json_value == nullptr);
290   const TraceBlobView& blob = ttp.blob_view;
291 
292   protos::pbzero::TracePacket::Decoder packet(blob.data(), blob.length());
293 
294   if (packet.has_process_tree())
295     ParseProcessTree(packet.process_tree());
296 
297   if (packet.has_process_stats())
298     ParseProcessStats(ts, packet.process_stats());
299 
300   if (packet.has_sys_stats())
301     ParseSysStats(ts, packet.sys_stats());
302 
303   if (packet.has_battery())
304     ParseBatteryCounters(ts, packet.battery());
305 
306   if (packet.has_power_rails())
307     ParsePowerRails(packet.power_rails());
308 
309   if (packet.has_trace_stats())
310     ParseTraceStats(packet.trace_stats());
311 
312   if (packet.has_ftrace_stats())
313     ParseFtraceStats(packet.ftrace_stats());
314 
315   if (packet.has_clock_snapshot())
316     ParseClockSnapshot(packet.clock_snapshot());
317 
318   if (packet.has_android_log())
319     ParseAndroidLogPacket(packet.android_log());
320 
321   if (packet.has_profile_packet())
322     ParseProfilePacket(packet.profile_packet());
323 
324   if (packet.has_system_info())
325     ParseSystemInfo(packet.system_info());
326 
327   if (packet.has_track_event()) {
328     ParseTrackEvent(ts, ttp.thread_timestamp, ttp.packet_sequence_state,
329                     packet.track_event());
330   }
331 
332   // TODO(lalitm): maybe move this to the flush method in the trace processor
333   // once we have it. This may reduce performance in the ArgsTracker though so
334   // needs to be handled carefully.
335   context_->args_tracker->Flush();
336   PERFETTO_DCHECK(!packet.bytes_left());
337 }
338 
ParseSysStats(int64_t ts,ConstBytes blob)339 void ProtoTraceParser::ParseSysStats(int64_t ts, ConstBytes blob) {
340   protos::pbzero::SysStats::Decoder sys_stats(blob.data, blob.size);
341 
342   for (auto it = sys_stats.meminfo(); it; ++it) {
343     protos::pbzero::SysStats::MeminfoValue::Decoder mi(it->data(), it->size());
344     auto key = static_cast<size_t>(mi.key());
345     if (PERFETTO_UNLIKELY(key >= meminfo_strs_id_.size())) {
346       PERFETTO_ELOG("MemInfo key %zu is not recognized.", key);
347       context_->storage->IncrementStats(stats::meminfo_unknown_keys);
348       continue;
349     }
350     // /proc/meminfo counters are in kB, convert to bytes
351     context_->event_tracker->PushCounter(
352         ts, mi.value() * 1024L, meminfo_strs_id_[key], 0, RefType::kRefNoRef);
353   }
354 
355   for (auto it = sys_stats.vmstat(); it; ++it) {
356     protos::pbzero::SysStats::VmstatValue::Decoder vm(it->data(), it->size());
357     auto key = static_cast<size_t>(vm.key());
358     if (PERFETTO_UNLIKELY(key >= vmstat_strs_id_.size())) {
359       PERFETTO_ELOG("VmStat key %zu is not recognized.", key);
360       context_->storage->IncrementStats(stats::vmstat_unknown_keys);
361       continue;
362     }
363     context_->event_tracker->PushCounter(ts, vm.value(), vmstat_strs_id_[key],
364                                          0, RefType::kRefNoRef);
365   }
366 
367   for (auto it = sys_stats.cpu_stat(); it; ++it) {
368     protos::pbzero::SysStats::CpuTimes::Decoder ct(it->data(), it->size());
369     if (PERFETTO_UNLIKELY(!ct.has_cpu_id())) {
370       PERFETTO_ELOG("CPU field not found in CpuTimes");
371       context_->storage->IncrementStats(stats::invalid_cpu_times);
372       continue;
373     }
374     context_->event_tracker->PushCounter(ts, ct.user_ns(),
375                                          cpu_times_user_ns_id_, ct.cpu_id(),
376                                          RefType::kRefCpuId);
377     context_->event_tracker->PushCounter(ts, ct.user_ice_ns(),
378                                          cpu_times_user_nice_ns_id_,
379                                          ct.cpu_id(), RefType::kRefCpuId);
380     context_->event_tracker->PushCounter(ts, ct.system_mode_ns(),
381                                          cpu_times_system_mode_ns_id_,
382                                          ct.cpu_id(), RefType::kRefCpuId);
383     context_->event_tracker->PushCounter(ts, ct.idle_ns(),
384                                          cpu_times_idle_ns_id_, ct.cpu_id(),
385                                          RefType::kRefCpuId);
386     context_->event_tracker->PushCounter(ts, ct.io_wait_ns(),
387                                          cpu_times_io_wait_ns_id_, ct.cpu_id(),
388                                          RefType::kRefCpuId);
389     context_->event_tracker->PushCounter(ts, ct.irq_ns(), cpu_times_irq_ns_id_,
390                                          ct.cpu_id(), RefType::kRefCpuId);
391     context_->event_tracker->PushCounter(ts, ct.softirq_ns(),
392                                          cpu_times_softirq_ns_id_, ct.cpu_id(),
393                                          RefType::kRefCpuId);
394   }
395 
396   for (auto it = sys_stats.num_irq(); it; ++it) {
397     protos::pbzero::SysStats::InterruptCount::Decoder ic(it->data(),
398                                                          it->size());
399     context_->event_tracker->PushCounter(ts, ic.count(), num_irq_name_id_,
400                                          ic.irq(), RefType::kRefIrq);
401   }
402 
403   for (auto it = sys_stats.num_softirq(); it; ++it) {
404     protos::pbzero::SysStats::InterruptCount::Decoder ic(it->data(),
405                                                          it->size());
406     context_->event_tracker->PushCounter(ts, ic.count(), num_softirq_name_id_,
407                                          ic.irq(), RefType::kRefSoftIrq);
408   }
409 
410   if (sys_stats.has_num_forks()) {
411     context_->event_tracker->PushCounter(
412         ts, sys_stats.num_forks(), num_forks_name_id_, 0, RefType::kRefNoRef);
413   }
414 
415   if (sys_stats.has_num_irq_total()) {
416     context_->event_tracker->PushCounter(ts, sys_stats.num_irq_total(),
417                                          num_irq_total_name_id_, 0,
418                                          RefType::kRefNoRef);
419   }
420 
421   if (sys_stats.has_num_softirq_total()) {
422     context_->event_tracker->PushCounter(ts, sys_stats.num_softirq_total(),
423                                          num_softirq_total_name_id_, 0,
424                                          RefType::kRefNoRef);
425   }
426 }
427 
ParseProcessTree(ConstBytes blob)428 void ProtoTraceParser::ParseProcessTree(ConstBytes blob) {
429   protos::pbzero::ProcessTree::Decoder ps(blob.data, blob.size);
430 
431   for (auto it = ps.processes(); it; ++it) {
432     protos::pbzero::ProcessTree::Process::Decoder proc(it->data(), it->size());
433     if (!proc.has_cmdline())
434       continue;
435     auto pid = static_cast<uint32_t>(proc.pid());
436     auto ppid = static_cast<uint32_t>(proc.ppid());
437 
438     context_->process_tracker->UpdateProcess(pid, ppid,
439                                              proc.cmdline()->as_string());
440   }
441 
442   for (auto it = ps.threads(); it; ++it) {
443     protos::pbzero::ProcessTree::Thread::Decoder thd(it->data(), it->size());
444     auto tid = static_cast<uint32_t>(thd.tid());
445     auto tgid = static_cast<uint32_t>(thd.tgid());
446     context_->process_tracker->UpdateThread(tid, tgid);
447   }
448 }
449 
ParseProcessStats(int64_t ts,ConstBytes blob)450 void ProtoTraceParser::ParseProcessStats(int64_t ts, ConstBytes blob) {
451   protos::pbzero::ProcessStats::Decoder stats(blob.data, blob.size);
452   const auto kOomScoreAdjFieldNumber =
453       protos::pbzero::ProcessStats::Process::kOomScoreAdjFieldNumber;
454   for (auto it = stats.processes(); it; ++it) {
455     // Maps a process counter field it to its value.
456     // E.g., 4 := 1024 -> "mem.rss.anon" := 1024.
457     std::array<int64_t, kProcStatsProcessSize> counter_values{};
458     std::array<bool, kProcStatsProcessSize> has_counter{};
459 
460     ProtoDecoder proc(it->data(), it->size());
461     uint32_t pid = 0;
462     for (auto fld = proc.ReadField(); fld.valid(); fld = proc.ReadField()) {
463       if (fld.id() == protos::pbzero::ProcessStats::Process::kPidFieldNumber) {
464         pid = fld.as_uint32();
465         continue;
466       }
467       bool is_counter_field = fld.id() < proc_stats_process_names_.size() &&
468                               proc_stats_process_names_[fld.id()] != 0;
469       if (is_counter_field) {
470         // Memory counters are in KB, keep values in bytes in the trace
471         // processor.
472         counter_values[fld.id()] = fld.id() == kOomScoreAdjFieldNumber
473                                        ? fld.as_int64()
474                                        : fld.as_int64() * 1024;
475         has_counter[fld.id()] = true;
476       } else {
477         context_->storage->IncrementStats(stats::proc_stat_unknown_counters);
478       }
479     }
480 
481     // Skip field_id 0 (invalid) and 1 (pid).
482     for (size_t field_id = 2; field_id < counter_values.size(); field_id++) {
483       if (!has_counter[field_id])
484         continue;
485 
486       // Lookup the interned string id from the field name using the
487       // pre-cached |proc_stats_process_names_| map.
488       StringId name = proc_stats_process_names_[field_id];
489       int64_t value = counter_values[field_id];
490       UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
491       context_->event_tracker->PushCounter(ts, value, name, upid,
492                                            RefType::kRefUpid);
493     }
494   }
495 }
496 
ParseFtracePacket(uint32_t cpu,int64_t ts,TraceSorter::TimestampedTracePiece ttp)497 void ProtoTraceParser::ParseFtracePacket(
498     uint32_t cpu,
499     int64_t ts,
500     TraceSorter::TimestampedTracePiece ttp) {
501   PERFETTO_DCHECK(ttp.json_value == nullptr);
502   const TraceBlobView& ftrace = ttp.blob_view;
503 
504   ProtoDecoder decoder(ftrace.data(), ftrace.length());
505   uint64_t raw_pid = 0;
506   if (auto pid_field =
507           decoder.FindField(protos::pbzero::FtraceEvent::kPidFieldNumber)) {
508     raw_pid = pid_field.as_uint64();
509   } else {
510     PERFETTO_ELOG("Pid field not found in ftrace packet");
511     return;
512   }
513   uint32_t pid = static_cast<uint32_t>(raw_pid);
514 
515   for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
516     bool is_metadata_field =
517         fld.id() == protos::pbzero::FtraceEvent::kPidFieldNumber ||
518         fld.id() == protos::pbzero::FtraceEvent::kTimestampFieldNumber;
519     if (is_metadata_field)
520       continue;
521 
522     ConstBytes data = fld.as_bytes();
523     if (fld.id() == protos::pbzero::FtraceEvent::kGenericFieldNumber) {
524       ParseGenericFtrace(ts, cpu, pid, data);
525     } else if (fld.id() !=
526                protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber) {
527       ParseTypedFtraceToRaw(fld.id(), ts, cpu, pid, data);
528     }
529 
530     switch (fld.id()) {
531       case protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber: {
532         ParseSchedSwitch(cpu, ts, data);
533         break;
534       }
535       case protos::pbzero::FtraceEvent::kSchedWakeupFieldNumber: {
536         ParseSchedWakeup(ts, data);
537         break;
538       }
539       case protos::pbzero::FtraceEvent::kCpuFrequencyFieldNumber: {
540         ParseCpuFreq(ts, data);
541         break;
542       }
543       case protos::pbzero::FtraceEvent::kCpuIdleFieldNumber: {
544         ParseCpuIdle(ts, data);
545         break;
546       }
547       case protos::pbzero::FtraceEvent::kPrintFieldNumber: {
548         ParsePrint(cpu, ts, pid, data);
549         break;
550       }
551       case protos::pbzero::FtraceEvent::kRssStatFieldNumber: {
552         ParseRssStat(ts, pid, data);
553         break;
554       }
555       case protos::pbzero::FtraceEvent::kIonHeapGrowFieldNumber: {
556         ParseIonHeapGrowOrShrink(ts, pid, data, true);
557         break;
558       }
559       case protos::pbzero::FtraceEvent::kIonHeapShrinkFieldNumber: {
560         ParseIonHeapGrowOrShrink(ts, pid, data, false);
561         break;
562       }
563       case protos::pbzero::FtraceEvent::kSignalGenerateFieldNumber: {
564         ParseSignalGenerate(ts, data);
565         break;
566       }
567       case protos::pbzero::FtraceEvent::kSignalDeliverFieldNumber: {
568         ParseSignalDeliver(ts, pid, data);
569         break;
570       }
571       case protos::pbzero::FtraceEvent::kLowmemoryKillFieldNumber: {
572         ParseLowmemoryKill(ts, data);
573         break;
574       }
575       case protos::pbzero::FtraceEvent::kOomScoreAdjUpdateFieldNumber: {
576         ParseOOMScoreAdjUpdate(ts, data);
577         break;
578       }
579       case protos::pbzero::FtraceEvent::kMmEventRecordFieldNumber: {
580         ParseMmEventRecord(ts, pid, data);
581         break;
582       }
583       case protos::pbzero::FtraceEvent::kSysEnterFieldNumber: {
584         ParseSysEvent(ts, pid, true, data);
585         break;
586       }
587       case protos::pbzero::FtraceEvent::kSysExitFieldNumber: {
588         ParseSysEvent(ts, pid, false, data);
589         break;
590       }
591       case protos::pbzero::FtraceEvent::kTaskNewtaskFieldNumber: {
592         ParseTaskNewTask(ts, pid, data);
593         break;
594       }
595       case protos::pbzero::FtraceEvent::kTaskRenameFieldNumber: {
596         ParseTaskRename(data);
597         break;
598       }
599       default:
600         break;
601     }
602   }
603   // TODO(lalitm): maybe move this to the flush method in the trace processor
604   // once we have it. This may reduce performance in the ArgsTracker though so
605   // needs to be handled carefully.
606   context_->args_tracker->Flush();
607 
608   PERFETTO_DCHECK(!decoder.bytes_left());
609 }
610 
ParseSignalDeliver(int64_t ts,uint32_t pid,ConstBytes blob)611 void ProtoTraceParser::ParseSignalDeliver(int64_t ts,
612                                           uint32_t pid,
613                                           ConstBytes blob) {
614   protos::pbzero::SignalDeliverFtraceEvent::Decoder sig(blob.data, blob.size);
615   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
616   context_->event_tracker->PushInstant(ts, signal_deliver_id_, sig.sig(), utid,
617                                        RefType::kRefUtid);
618 }
619 
620 // This event has both the pid of the thread that sent the signal and the
621 // destination of the signal. Currently storing the pid of the destination.
ParseSignalGenerate(int64_t ts,ConstBytes blob)622 void ProtoTraceParser::ParseSignalGenerate(int64_t ts, ConstBytes blob) {
623   protos::pbzero::SignalGenerateFtraceEvent::Decoder sig(blob.data, blob.size);
624 
625   UniqueTid utid = context_->process_tracker->GetOrCreateThread(
626       static_cast<uint32_t>(sig.pid()));
627   context_->event_tracker->PushInstant(ts, signal_generate_id_, sig.sig(), utid,
628                                        RefType::kRefUtid);
629 }
630 
ParseLowmemoryKill(int64_t ts,ConstBytes blob)631 void ProtoTraceParser::ParseLowmemoryKill(int64_t ts, ConstBytes blob) {
632   // TODO(taylori): Store the pagecache_size, pagecache_limit and free fields
633   // in an args table
634   protos::pbzero::LowmemoryKillFtraceEvent::Decoder lmk(blob.data, blob.size);
635 
636   // Store the pid of the event that is lmk-ed.
637   auto pid = static_cast<uint32_t>(lmk.pid());
638   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
639   auto row_id = context_->event_tracker->PushInstant(ts, lmk_id_, 0, utid,
640                                                      RefType::kRefUtid, true);
641 
642   // Store the comm as an arg.
643   auto comm_id = context_->storage->InternString(
644       lmk.has_comm() ? lmk.comm() : base::StringView());
645   context_->args_tracker->AddArg(row_id, comm_name_id_, comm_name_id_,
646                                  Variadic::String(comm_id));
647 }
648 
ParseRssStat(int64_t ts,uint32_t pid,ConstBytes blob)649 void ProtoTraceParser::ParseRssStat(int64_t ts, uint32_t pid, ConstBytes blob) {
650   protos::pbzero::RssStatFtraceEvent::Decoder rss(blob.data, blob.size);
651   const auto kRssStatUnknown = static_cast<uint32_t>(rss_members_.size()) - 1;
652   auto member = static_cast<uint32_t>(rss.member());
653   int64_t size = rss.size();
654   if (member >= rss_members_.size()) {
655     context_->storage->IncrementStats(stats::rss_stat_unknown_keys);
656     member = kRssStatUnknown;
657   }
658 
659   if (size >= 0) {
660     UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
661     context_->event_tracker->PushCounter(ts, size, rss_members_[member], utid,
662                                          RefType::kRefUtid, true);
663   } else {
664     context_->storage->IncrementStats(stats::rss_stat_negative_size);
665   }
666 }
667 
ParseIonHeapGrowOrShrink(int64_t ts,uint32_t pid,ConstBytes blob,bool grow)668 void ProtoTraceParser::ParseIonHeapGrowOrShrink(int64_t ts,
669                                                 uint32_t pid,
670                                                 ConstBytes blob,
671                                                 bool grow) {
672   protos::pbzero::IonHeapGrowFtraceEvent::Decoder ion(blob.data, blob.size);
673   int64_t total_bytes = ion.total_allocated();
674   int64_t change_bytes = static_cast<int64_t>(ion.len()) * (grow ? 1 : -1);
675   StringId global_name_id = ion_total_unknown_id_;
676   StringId change_name_id = ion_change_unknown_id_;
677 
678   if (ion.has_heap_name()) {
679     char counter_name[255];
680     base::StringView heap_name = ion.heap_name();
681     snprintf(counter_name, sizeof(counter_name), "mem.ion.%.*s",
682              int(heap_name.size()), heap_name.data());
683     global_name_id = context_->storage->InternString(counter_name);
684     snprintf(counter_name, sizeof(counter_name), "mem.ion_change.%.*s",
685              int(heap_name.size()), heap_name.data());
686     change_name_id = context_->storage->InternString(counter_name);
687   }
688 
689   // Push the global counter.
690   context_->event_tracker->PushCounter(ts, total_bytes, global_name_id, 0,
691                                        RefType::kRefNoRef);
692 
693   // Push the change counter.
694   // TODO(b/121331269): these should really be instant events. For now we
695   // manually reset them to 0 after 1ns.
696   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
697   context_->event_tracker->PushCounter(ts, change_bytes, change_name_id, utid,
698                                        RefType::kRefUtid);
699   context_->event_tracker->PushCounter(ts + 1, 0, change_name_id, utid,
700                                        RefType::kRefUtid);
701 
702   // We are reusing the same function for ion_heap_grow and ion_heap_shrink.
703   // It is fine as the arguments are the same, but we need to be sure that the
704   // protobuf field id for both are the same.
705   static_assert(
706       static_cast<int>(
707           protos::pbzero::IonHeapGrowFtraceEvent::kTotalAllocatedFieldNumber) ==
708               static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
709                                    kTotalAllocatedFieldNumber) &&
710           static_cast<int>(
711               protos::pbzero::IonHeapGrowFtraceEvent::kLenFieldNumber) ==
712               static_cast<int>(
713                   protos::pbzero::IonHeapShrinkFtraceEvent::kLenFieldNumber) &&
714           static_cast<int>(
715               protos::pbzero::IonHeapGrowFtraceEvent::kHeapNameFieldNumber) ==
716               static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
717                                    kHeapNameFieldNumber),
718       "ION field mismatch");
719 }
720 
ParseCpuFreq(int64_t ts,ConstBytes blob)721 void ProtoTraceParser::ParseCpuFreq(int64_t ts, ConstBytes blob) {
722   protos::pbzero::CpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
723   uint32_t cpu = freq.cpu_id();
724   uint32_t new_freq = freq.state();
725   context_->event_tracker->PushCounter(ts, new_freq, cpu_freq_name_id_, cpu,
726                                        RefType::kRefCpuId);
727 }
728 
ParseCpuIdle(int64_t ts,ConstBytes blob)729 void ProtoTraceParser::ParseCpuIdle(int64_t ts, ConstBytes blob) {
730   protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob.data, blob.size);
731   uint32_t cpu = idle.cpu_id();
732   uint32_t new_state = idle.state();
733   context_->event_tracker->PushCounter(ts, new_state, cpu_idle_name_id_, cpu,
734                                        RefType::kRefCpuId);
735 }
736 
737 PERFETTO_ALWAYS_INLINE
ParseSchedSwitch(uint32_t cpu,int64_t ts,ConstBytes blob)738 void ProtoTraceParser::ParseSchedSwitch(uint32_t cpu,
739                                         int64_t ts,
740                                         ConstBytes blob) {
741   protos::pbzero::SchedSwitchFtraceEvent::Decoder ss(blob.data, blob.size);
742   uint32_t prev_pid = static_cast<uint32_t>(ss.prev_pid());
743   uint32_t next_pid = static_cast<uint32_t>(ss.next_pid());
744   context_->event_tracker->PushSchedSwitch(
745       cpu, ts, prev_pid, ss.prev_comm(), ss.prev_prio(), ss.prev_state(),
746       next_pid, ss.next_comm(), ss.next_prio());
747 }
748 
ParseSchedWakeup(int64_t ts,ConstBytes blob)749 void ProtoTraceParser::ParseSchedWakeup(int64_t ts, ConstBytes blob) {
750   protos::pbzero::SchedWakeupFtraceEvent::Decoder sw(blob.data, blob.size);
751   uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
752   StringId name_id = context_->storage->InternString(sw.comm());
753   auto utid = context_->process_tracker->UpdateThreadName(wakee_pid, name_id);
754   context_->event_tracker->PushInstant(ts, sched_wakeup_name_id_, 0 /* value */,
755                                        utid, RefType::kRefUtid);
756 }
757 
ParseTaskNewTask(int64_t ts,uint32_t source_tid,ConstBytes blob)758 void ProtoTraceParser::ParseTaskNewTask(int64_t ts,
759                                         uint32_t source_tid,
760                                         ConstBytes blob) {
761   protos::pbzero::TaskNewtaskFtraceEvent::Decoder evt(blob.data, blob.size);
762   uint32_t clone_flags = static_cast<uint32_t>(evt.clone_flags());
763   uint32_t new_tid = static_cast<uint32_t>(evt.pid());
764   StringId new_comm = context_->storage->InternString(evt.comm());
765   auto* proc_tracker = context_->process_tracker.get();
766 
767   // task_newtask is raised both in the case of a new process creation (fork()
768   // family) and thread creation (clone(CLONE_THREAD, ...)).
769   static const uint32_t kCloneThread = 0x00010000;  // From kernel's sched.h.
770   if ((clone_flags & kCloneThread) == 0) {
771     // This is a plain-old fork() or equivalent.
772     proc_tracker->StartNewProcess(ts, new_tid);
773     return;
774   }
775 
776   // This is a pthread_create or similar. Bind the two threads together, so
777   // they get resolved to the same process.
778   auto source_utid = proc_tracker->GetOrCreateThread(source_tid);
779   auto new_utid = proc_tracker->StartNewThread(ts, new_tid, new_comm);
780   proc_tracker->AssociateThreads(source_utid, new_utid);
781 }
782 
ParseTaskRename(ConstBytes blob)783 void ProtoTraceParser::ParseTaskRename(ConstBytes blob) {
784   protos::pbzero::TaskRenameFtraceEvent::Decoder evt(blob.data, blob.size);
785   uint32_t tid = static_cast<uint32_t>(evt.pid());
786   StringId comm = context_->storage->InternString(evt.newcomm());
787   context_->process_tracker->UpdateThreadName(tid, comm);
788 }
789 
ParsePrint(uint32_t,int64_t ts,uint32_t pid,ConstBytes blob)790 void ProtoTraceParser::ParsePrint(uint32_t,
791                                   int64_t ts,
792                                   uint32_t pid,
793                                   ConstBytes blob) {
794   protos::pbzero::PrintFtraceEvent::Decoder evt(blob.data, blob.size);
795   SystraceTracePoint point{};
796   auto r = ParseSystraceTracePoint(evt.buf(), &point);
797   if (r != SystraceParseResult::kSuccess) {
798     if (r == SystraceParseResult::kFailure) {
799       context_->storage->IncrementStats(stats::systrace_parse_failure);
800     }
801     return;
802   }
803 
804   switch (point.phase) {
805     case 'B': {
806       StringId name_id = context_->storage->InternString(point.name);
807       context_->slice_tracker->BeginAndroid(ts, pid, point.tgid, 0 /*cat_id*/,
808                                             name_id);
809       break;
810     }
811 
812     case 'E': {
813       context_->slice_tracker->EndAndroid(ts, pid, point.tgid);
814       break;
815     }
816 
817     case 'C': {
818       // LMK events from userspace are hacked as counter events with the "value"
819       // of the counter representing the pid of the killed process which is
820       // reset to 0 once the kill is complete.
821       // Homogenise this with kernel LMK events as an instant event, ignoring
822       // the resets to 0.
823       if (point.name == "kill_one_process") {
824         auto killed_pid = static_cast<uint32_t>(point.value);
825         if (killed_pid != 0) {
826           UniquePid killed_upid =
827               context_->process_tracker->GetOrCreateProcess(killed_pid);
828           context_->event_tracker->PushInstant(ts, lmk_id_, 0, killed_upid,
829                                                RefType::kRefUpid);
830         }
831         // TODO(lalitm): we should not add LMK events to the counters table
832         // once the UI has support for displaying instants.
833       }
834       // This is per upid on purpose. Some counters are pushed from arbitrary
835       // threads but are really per process.
836       UniquePid upid =
837           context_->process_tracker->GetOrCreateProcess(point.tgid);
838       StringId name_id = context_->storage->InternString(point.name);
839       context_->event_tracker->PushCounter(ts, point.value, name_id, upid,
840                                            RefType::kRefUpid);
841     }
842   }
843 }
844 
ParseBatteryCounters(int64_t ts,ConstBytes blob)845 void ProtoTraceParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
846   protos::pbzero::BatteryCounters::Decoder evt(blob.data, blob.size);
847   if (evt.has_charge_counter_uah()) {
848     context_->event_tracker->PushCounter(
849         ts, evt.charge_counter_uah(), batt_charge_id_, 0, RefType::kRefNoRef);
850   }
851   if (evt.has_capacity_percent()) {
852     context_->event_tracker->PushCounter(
853         ts, static_cast<double>(evt.capacity_percent()), batt_capacity_id_, 0,
854         RefType::kRefNoRef);
855   }
856   if (evt.has_current_ua()) {
857     context_->event_tracker->PushCounter(ts, evt.current_ua(), batt_current_id_,
858                                          0, RefType::kRefNoRef);
859   }
860   if (evt.has_current_avg_ua()) {
861     context_->event_tracker->PushCounter(
862         ts, evt.current_avg_ua(), batt_current_avg_id_, 0, RefType::kRefNoRef);
863   }
864 }
865 
ParsePowerRails(ConstBytes blob)866 void ProtoTraceParser::ParsePowerRails(ConstBytes blob) {
867   protos::pbzero::PowerRails::Decoder evt(blob.data, blob.size);
868   if (evt.has_rail_descriptor()) {
869     for (auto it = evt.rail_descriptor(); it; ++it) {
870       protos::pbzero::PowerRails::RailDescriptor::Decoder desc(it->data(),
871                                                                it->size());
872       uint32_t idx = desc.index();
873       if (PERFETTO_UNLIKELY(idx > 256)) {
874         PERFETTO_DLOG("Skipping excessively large power_rail index %" PRIu32,
875                       idx);
876         continue;
877       }
878       if (power_rails_strs_id_.size() <= idx)
879         power_rails_strs_id_.resize(idx + 1);
880       char counter_name[255];
881       snprintf(counter_name, sizeof(counter_name), "power.%.*s_uws",
882                int(desc.rail_name().size), desc.rail_name().data);
883       power_rails_strs_id_[idx] = context_->storage->InternString(counter_name);
884     }
885   }
886 
887   if (evt.has_energy_data()) {
888     for (auto it = evt.energy_data(); it; ++it) {
889       protos::pbzero::PowerRails::EnergyData::Decoder desc(it->data(),
890                                                            it->size());
891       if (desc.index() < power_rails_strs_id_.size()) {
892         int64_t ts = static_cast<int64_t>(desc.timestamp_ms()) * 1000000;
893         context_->event_tracker->PushCounter(ts, desc.energy(),
894                                              power_rails_strs_id_[desc.index()],
895                                              0, RefType::kRefNoRef);
896       } else {
897         context_->storage->IncrementStats(stats::power_rail_unknown_index);
898       }
899     }
900   }
901 }
902 
ParseOOMScoreAdjUpdate(int64_t ts,ConstBytes blob)903 void ProtoTraceParser::ParseOOMScoreAdjUpdate(int64_t ts, ConstBytes blob) {
904   protos::pbzero::OomScoreAdjUpdateFtraceEvent::Decoder evt(blob.data,
905                                                             blob.size);
906   // The int16_t static cast is because older version of the on-device tracer
907   // had a bug on negative varint encoding (b/120618641).
908   int16_t oom_adj = static_cast<int16_t>(evt.oom_score_adj());
909   uint32_t pid = static_cast<uint32_t>(evt.pid());
910   UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
911   context_->event_tracker->PushCounter(ts, oom_adj, oom_score_adj_id_, upid,
912                                        RefType::kRefUpid);
913 }
914 
ParseMmEventRecord(int64_t ts,uint32_t pid,ConstBytes blob)915 void ProtoTraceParser::ParseMmEventRecord(int64_t ts,
916                                           uint32_t pid,
917                                           ConstBytes blob) {
918   protos::pbzero::MmEventRecordFtraceEvent::Decoder evt(blob.data, blob.size);
919   uint32_t type = evt.type();
920   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
921 
922   if (type >= mm_event_counter_names_.size()) {
923     context_->storage->IncrementStats(stats::mm_unknown_type);
924     return;
925   }
926 
927   const auto& counter_names = mm_event_counter_names_[type];
928   context_->event_tracker->PushCounter(ts, evt.count(), counter_names.count,
929                                        utid, RefType::kRefUtid, true);
930   context_->event_tracker->PushCounter(ts, evt.max_lat(), counter_names.max_lat,
931                                        utid, RefType::kRefUtid, true);
932   context_->event_tracker->PushCounter(ts, evt.avg_lat(), counter_names.avg_lat,
933                                        utid, RefType::kRefUtid, true);
934 }
935 
ParseSysEvent(int64_t ts,uint32_t pid,bool is_enter,ConstBytes blob)936 void ProtoTraceParser::ParseSysEvent(int64_t ts,
937                                      uint32_t pid,
938                                      bool is_enter,
939                                      ConstBytes blob) {
940   protos::pbzero::SysEnterFtraceEvent::Decoder evt(blob.data, blob.size);
941   uint32_t syscall_num = static_cast<uint32_t>(evt.id());
942   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
943 
944   if (is_enter) {
945     context_->syscall_tracker->Enter(ts, utid, syscall_num);
946   } else {
947     context_->syscall_tracker->Exit(ts, utid, syscall_num);
948   }
949 
950   // We are reusing the same function for sys_enter and sys_exit.
951   // It is fine as the arguments are the same, but we need to be sure that the
952   // protobuf field id for both are the same.
953   static_assert(
954       static_cast<int>(protos::pbzero::SysEnterFtraceEvent::kIdFieldNumber) ==
955           static_cast<int>(protos::pbzero::SysExitFtraceEvent::kIdFieldNumber),
956       "field mismatch");
957 }
958 
ParseGenericFtrace(int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)959 void ProtoTraceParser::ParseGenericFtrace(int64_t ts,
960                                           uint32_t cpu,
961                                           uint32_t tid,
962                                           ConstBytes blob) {
963   protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
964   StringId event_id = context_->storage->InternString(evt.event_name());
965   UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
966   RowId row_id = context_->storage->mutable_raw_events()->AddRawEvent(
967       ts, event_id, cpu, utid);
968 
969   for (auto it = evt.field(); it; ++it) {
970     protos::pbzero::GenericFtraceEvent::Field::Decoder fld(it->data(),
971                                                            it->size());
972     auto field_name_id = context_->storage->InternString(fld.name());
973     if (fld.has_int_value()) {
974       context_->args_tracker->AddArg(row_id, field_name_id, field_name_id,
975                                      Variadic::Integer(fld.int_value()));
976     } else if (fld.has_uint_value()) {
977       context_->args_tracker->AddArg(
978           row_id, field_name_id, field_name_id,
979           Variadic::Integer(static_cast<int64_t>(fld.uint_value())));
980     } else if (fld.has_str_value()) {
981       StringId str_value = context_->storage->InternString(fld.str_value());
982       context_->args_tracker->AddArg(row_id, field_name_id, field_name_id,
983                                      Variadic::String(str_value));
984     }
985   }
986 }
987 
ParseTypedFtraceToRaw(uint32_t ftrace_id,int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)988 void ProtoTraceParser::ParseTypedFtraceToRaw(uint32_t ftrace_id,
989                                              int64_t ts,
990                                              uint32_t cpu,
991                                              uint32_t tid,
992                                              ConstBytes blob) {
993   ProtoDecoder decoder(blob.data, blob.size);
994   if (ftrace_id >= GetDescriptorsSize()) {
995     PERFETTO_DLOG("Event with id: %d does not exist and cannot be parsed.",
996                   ftrace_id);
997     return;
998   }
999 
1000   MessageDescriptor* m = GetMessageDescriptorForId(ftrace_id);
1001   const auto& message_strings = ftrace_message_strings_[ftrace_id];
1002   UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
1003   RowId raw_event_id = context_->storage->mutable_raw_events()->AddRawEvent(
1004       ts, message_strings.message_name_id, cpu, utid);
1005   for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
1006     if (PERFETTO_UNLIKELY(fld.id() >= kMaxFtraceEventFields)) {
1007       PERFETTO_DLOG(
1008           "Skipping ftrace arg - proto field id is too large (%" PRIu16 ")",
1009           fld.id());
1010       continue;
1011     }
1012     ProtoSchemaType type = m->fields[fld.id()].type;
1013     StringId name_id = message_strings.field_name_ids[fld.id()];
1014     switch (type) {
1015       case ProtoSchemaType::kUint32:
1016       case ProtoSchemaType::kInt32:
1017       case ProtoSchemaType::kUint64:
1018       case ProtoSchemaType::kInt64:
1019       case ProtoSchemaType::kFixed64:
1020       case ProtoSchemaType::kFixed32:
1021       case ProtoSchemaType::kSfixed32:
1022       case ProtoSchemaType::kSfixed64:
1023       case ProtoSchemaType::kSint32:
1024       case ProtoSchemaType::kSint64:
1025       case ProtoSchemaType::kBool:
1026       case ProtoSchemaType::kEnum: {
1027         context_->args_tracker->AddArg(raw_event_id, name_id, name_id,
1028                                        Variadic::Integer(fld.as_int64()));
1029         break;
1030       }
1031       case ProtoSchemaType::kString:
1032       case ProtoSchemaType::kBytes: {
1033         StringId value = context_->storage->InternString(fld.as_string());
1034         context_->args_tracker->AddArg(raw_event_id, name_id, name_id,
1035                                        Variadic::String(value));
1036         break;
1037       }
1038       case ProtoSchemaType::kDouble: {
1039         context_->args_tracker->AddArg(raw_event_id, name_id, name_id,
1040                                        Variadic::Real(fld.as_double()));
1041         break;
1042       }
1043       case ProtoSchemaType::kFloat: {
1044         context_->args_tracker->AddArg(
1045             raw_event_id, name_id, name_id,
1046             Variadic::Real(static_cast<double>(fld.as_float())));
1047         break;
1048       }
1049       case ProtoSchemaType::kUnknown:
1050       case ProtoSchemaType::kGroup:
1051       case ProtoSchemaType::kMessage:
1052         PERFETTO_DLOG("Could not store %s as a field in args table.",
1053                       ProtoSchemaToString(type));
1054         break;
1055     }
1056   }
1057 }
1058 
ParseClockSnapshot(ConstBytes blob)1059 void ProtoTraceParser::ParseClockSnapshot(ConstBytes blob) {
1060   protos::pbzero::ClockSnapshot::Decoder evt(blob.data, blob.size);
1061   int64_t clock_boottime = 0;
1062   int64_t clock_monotonic = 0;
1063   int64_t clock_realtime = 0;
1064   for (auto it = evt.clocks(); it; ++it) {
1065     protos::pbzero::ClockSnapshot::Clock::Decoder clk(it->data(), it->size());
1066     if (clk.type() == protos::pbzero::ClockSnapshot::Clock::BOOTTIME) {
1067       clock_boottime = static_cast<int64_t>(clk.timestamp());
1068     } else if (clk.type() == protos::pbzero::ClockSnapshot::Clock::REALTIME) {
1069       clock_realtime = static_cast<int64_t>(clk.timestamp());
1070     } else if (clk.type() == protos::pbzero::ClockSnapshot::Clock::MONOTONIC) {
1071       clock_monotonic = static_cast<int64_t>(clk.timestamp());
1072     }
1073   }
1074 
1075   // Usually these snapshots come all together.
1076   PERFETTO_DCHECK(clock_boottime > 0 && clock_monotonic > 0 &&
1077                   clock_realtime > 0);
1078 
1079   if (clock_boottime <= 0) {
1080     PERFETTO_ELOG("ClockSnapshot has an invalid BOOTTIME (%" PRId64 ")",
1081                   clock_boottime);
1082     context_->storage->IncrementStats(stats::invalid_clock_snapshots);
1083     return;
1084   }
1085 
1086   auto* ct = context_->clock_tracker.get();
1087 
1088   // |clock_boottime| is used as the reference trace time.
1089   ct->SyncClocks(ClockDomain::kBootTime, clock_boottime, clock_boottime);
1090 
1091   if (clock_monotonic > 0)
1092     ct->SyncClocks(ClockDomain::kMonotonic, clock_monotonic, clock_boottime);
1093 
1094   if (clock_realtime > 0)
1095     ct->SyncClocks(ClockDomain::kRealTime, clock_realtime, clock_boottime);
1096 }
1097 
ParseAndroidLogPacket(ConstBytes blob)1098 void ProtoTraceParser::ParseAndroidLogPacket(ConstBytes blob) {
1099   protos::pbzero::AndroidLogPacket::Decoder packet(blob.data, blob.size);
1100   for (auto it = packet.events(); it; ++it)
1101     ParseAndroidLogEvent(it->as_bytes());
1102 
1103   if (packet.has_stats())
1104     ParseAndroidLogStats(packet.stats());
1105 }
1106 
ParseAndroidLogEvent(ConstBytes blob)1107 void ProtoTraceParser::ParseAndroidLogEvent(ConstBytes blob) {
1108   // TODO(primiano): Add events and non-stringified fields to the "raw" table.
1109   protos::pbzero::AndroidLogPacket::LogEvent::Decoder evt(blob.data, blob.size);
1110   int64_t ts = static_cast<int64_t>(evt.timestamp());
1111   uint32_t pid = static_cast<uint32_t>(evt.pid());
1112   uint32_t tid = static_cast<uint32_t>(evt.tid());
1113   uint8_t prio = static_cast<uint8_t>(evt.prio());
1114   StringId tag_id = context_->storage->InternString(
1115       evt.has_tag() ? evt.tag() : base::StringView());
1116   StringId msg_id = context_->storage->InternString(
1117       evt.has_message() ? evt.message() : base::StringView());
1118 
1119   char arg_msg[4096];
1120   char* arg_str = &arg_msg[0];
1121   *arg_str = '\0';
1122   auto arg_avail = [&arg_msg, &arg_str]() {
1123     return sizeof(arg_msg) - static_cast<size_t>(arg_str - arg_msg);
1124   };
1125   for (auto it = evt.args(); it; ++it) {
1126     protos::pbzero::AndroidLogPacket::LogEvent::Arg::Decoder arg(it->data(),
1127                                                                  it->size());
1128     if (!arg.has_name())
1129       continue;
1130     arg_str +=
1131         snprintf(arg_str, arg_avail(),
1132                  " %.*s=", static_cast<int>(arg.name().size), arg.name().data);
1133     if (arg.has_string_value()) {
1134       arg_str += snprintf(arg_str, arg_avail(), "\"%.*s\"",
1135                           static_cast<int>(arg.string_value().size),
1136                           arg.string_value().data);
1137     } else if (arg.has_int_value()) {
1138       arg_str += snprintf(arg_str, arg_avail(), "%" PRId64, arg.int_value());
1139     } else if (arg.has_float_value()) {
1140       arg_str += snprintf(arg_str, arg_avail(), "%f",
1141                           static_cast<double>(arg.float_value()));
1142     }
1143   }
1144 
1145   if (prio == 0)
1146     prio = protos::pbzero::AndroidLogPriority::PRIO_INFO;
1147 
1148   if (arg_str != &arg_msg[0]) {
1149     PERFETTO_DCHECK(!msg_id);
1150     // Skip the first space char (" foo=1 bar=2" -> "foo=1 bar=2").
1151     msg_id = context_->storage->InternString(&arg_msg[1]);
1152   }
1153   UniquePid utid = tid ? context_->process_tracker->UpdateThread(tid, pid) : 0;
1154   base::Optional<int64_t> opt_trace_time =
1155       context_->clock_tracker->ToTraceTime(ClockDomain::kRealTime, ts);
1156   if (!opt_trace_time)
1157     return;
1158 
1159   // Log events are NOT required to be sorted by trace_time. The virtual table
1160   // will take care of sorting on-demand.
1161   context_->storage->mutable_android_log()->AddLogEvent(
1162       opt_trace_time.value(), utid, prio, tag_id, msg_id);
1163 }
1164 
ParseAndroidLogStats(ConstBytes blob)1165 void ProtoTraceParser::ParseAndroidLogStats(ConstBytes blob) {
1166   protos::pbzero::AndroidLogPacket::Stats::Decoder evt(blob.data, blob.size);
1167   if (evt.has_num_failed()) {
1168     context_->storage->SetStats(stats::android_log_num_failed,
1169                                 static_cast<int64_t>(evt.num_failed()));
1170   }
1171 
1172   if (evt.has_num_skipped()) {
1173     context_->storage->SetStats(stats::android_log_num_skipped,
1174                                 static_cast<int64_t>(evt.num_skipped()));
1175   }
1176 
1177   if (evt.has_num_total()) {
1178     context_->storage->SetStats(stats::android_log_num_total,
1179                                 static_cast<int64_t>(evt.num_total()));
1180   }
1181 }
1182 
ParseTraceStats(ConstBytes blob)1183 void ProtoTraceParser::ParseTraceStats(ConstBytes blob) {
1184   protos::pbzero::TraceStats::Decoder evt(blob.data, blob.size);
1185   auto* storage = context_->storage.get();
1186   storage->SetStats(stats::traced_producers_connected,
1187                     static_cast<int64_t>(evt.producers_connected()));
1188   storage->SetStats(stats::traced_data_sources_registered,
1189                     static_cast<int64_t>(evt.data_sources_registered()));
1190   storage->SetStats(stats::traced_data_sources_seen,
1191                     static_cast<int64_t>(evt.data_sources_seen()));
1192   storage->SetStats(stats::traced_tracing_sessions,
1193                     static_cast<int64_t>(evt.tracing_sessions()));
1194   storage->SetStats(stats::traced_total_buffers,
1195                     static_cast<int64_t>(evt.total_buffers()));
1196   storage->SetStats(stats::traced_chunks_discarded,
1197                     static_cast<int64_t>(evt.chunks_discarded()));
1198   storage->SetStats(stats::traced_patches_discarded,
1199                     static_cast<int64_t>(evt.patches_discarded()));
1200 
1201   int buf_num = 0;
1202   for (auto it = evt.buffer_stats(); it; ++it, ++buf_num) {
1203     protos::pbzero::TraceStats::BufferStats::Decoder buf(it->data(),
1204                                                          it->size());
1205     storage->SetIndexedStats(stats::traced_buf_buffer_size, buf_num,
1206                              static_cast<int64_t>(buf.buffer_size()));
1207     storage->SetIndexedStats(stats::traced_buf_bytes_written, buf_num,
1208                              static_cast<int64_t>(buf.bytes_written()));
1209     storage->SetIndexedStats(stats::traced_buf_bytes_overwritten, buf_num,
1210                              static_cast<int64_t>(buf.bytes_overwritten()));
1211     storage->SetIndexedStats(stats::traced_buf_bytes_read, buf_num,
1212                              static_cast<int64_t>(buf.bytes_read()));
1213     storage->SetIndexedStats(stats::traced_buf_padding_bytes_written, buf_num,
1214                              static_cast<int64_t>(buf.padding_bytes_written()));
1215     storage->SetIndexedStats(stats::traced_buf_padding_bytes_cleared, buf_num,
1216                              static_cast<int64_t>(buf.padding_bytes_cleared()));
1217     storage->SetIndexedStats(stats::traced_buf_chunks_written, buf_num,
1218                              static_cast<int64_t>(buf.chunks_written()));
1219     storage->SetIndexedStats(stats::traced_buf_chunks_rewritten, buf_num,
1220                              static_cast<int64_t>(buf.chunks_rewritten()));
1221     storage->SetIndexedStats(stats::traced_buf_chunks_overwritten, buf_num,
1222                              static_cast<int64_t>(buf.chunks_overwritten()));
1223     storage->SetIndexedStats(stats::traced_buf_chunks_discarded, buf_num,
1224                              static_cast<int64_t>(buf.chunks_discarded()));
1225     storage->SetIndexedStats(stats::traced_buf_chunks_read, buf_num,
1226                              static_cast<int64_t>(buf.chunks_read()));
1227     storage->SetIndexedStats(
1228         stats::traced_buf_chunks_committed_out_of_order, buf_num,
1229         static_cast<int64_t>(buf.chunks_committed_out_of_order()));
1230     storage->SetIndexedStats(stats::traced_buf_write_wrap_count, buf_num,
1231                              static_cast<int64_t>(buf.write_wrap_count()));
1232     storage->SetIndexedStats(stats::traced_buf_patches_succeeded, buf_num,
1233                              static_cast<int64_t>(buf.patches_succeeded()));
1234     storage->SetIndexedStats(stats::traced_buf_patches_failed, buf_num,
1235                              static_cast<int64_t>(buf.patches_failed()));
1236     storage->SetIndexedStats(stats::traced_buf_readaheads_succeeded, buf_num,
1237                              static_cast<int64_t>(buf.readaheads_succeeded()));
1238     storage->SetIndexedStats(stats::traced_buf_readaheads_failed, buf_num,
1239                              static_cast<int64_t>(buf.readaheads_failed()));
1240   }
1241 }
1242 
ParseFtraceStats(ConstBytes blob)1243 void ProtoTraceParser::ParseFtraceStats(ConstBytes blob) {
1244   protos::pbzero::FtraceStats::Decoder evt(blob.data, blob.size);
1245   size_t phase =
1246       evt.phase() == protos::pbzero::FtraceStats_Phase_END_OF_TRACE ? 1 : 0;
1247 
1248   // This code relies on the fact that each ftrace_cpu_XXX_end event is
1249   // just after the corresponding ftrace_cpu_XXX_begin event.
1250   static_assert(
1251       stats::ftrace_cpu_read_events_end - stats::ftrace_cpu_read_events_begin ==
1252               1 &&
1253           stats::ftrace_cpu_entries_end - stats::ftrace_cpu_entries_begin == 1,
1254       "ftrace_cpu_XXX stats definition are messed up");
1255 
1256   auto* storage = context_->storage.get();
1257   for (auto it = evt.cpu_stats(); it; ++it) {
1258     protos::pbzero::FtraceCpuStats::Decoder cpu_stats(it->data(), it->size());
1259     int cpu = static_cast<int>(cpu_stats.cpu());
1260     storage->SetIndexedStats(stats::ftrace_cpu_entries_begin + phase, cpu,
1261                              static_cast<int64_t>(cpu_stats.entries()));
1262     storage->SetIndexedStats(stats::ftrace_cpu_overrun_begin + phase, cpu,
1263                              static_cast<int64_t>(cpu_stats.overrun()));
1264     storage->SetIndexedStats(stats::ftrace_cpu_commit_overrun_begin + phase,
1265                              cpu,
1266                              static_cast<int64_t>(cpu_stats.commit_overrun()));
1267     storage->SetIndexedStats(stats::ftrace_cpu_bytes_read_begin + phase, cpu,
1268                              static_cast<int64_t>(cpu_stats.bytes_read()));
1269 
1270     // oldest_event_ts can often be set to very high values, possibly because
1271     // of wrapping. Ensure that we are not overflowing to avoid ubsan
1272     // complaining.
1273     double oldest_event_ts = cpu_stats.oldest_event_ts() * 1e9;
1274     if (oldest_event_ts >= std::numeric_limits<int64_t>::max()) {
1275       storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
1276                                cpu, std::numeric_limits<int64_t>::max());
1277     } else {
1278       storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
1279                                cpu, static_cast<int64_t>(oldest_event_ts));
1280     }
1281 
1282     storage->SetIndexedStats(stats::ftrace_cpu_now_ts_begin + phase, cpu,
1283                              static_cast<int64_t>(cpu_stats.now_ts() * 1e9));
1284     storage->SetIndexedStats(stats::ftrace_cpu_dropped_events_begin + phase,
1285                              cpu,
1286                              static_cast<int64_t>(cpu_stats.dropped_events()));
1287     storage->SetIndexedStats(stats::ftrace_cpu_read_events_begin + phase, cpu,
1288                              static_cast<int64_t>(cpu_stats.read_events()));
1289   }
1290 }
1291 
ParseProfilePacket(ConstBytes blob)1292 void ProtoTraceParser::ParseProfilePacket(ConstBytes blob) {
1293   uint64_t index = 0;
1294   protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
1295 
1296   for (auto it = packet.strings(); it; ++it) {
1297     protos::pbzero::ProfilePacket::InternedString::Decoder entry(it->data(),
1298                                                                  it->size());
1299 
1300     const char* str = reinterpret_cast<const char*>(entry.str().data);
1301     auto str_id = context_->storage->InternString(
1302         base::StringView(str, entry.str().size));
1303     context_->heap_profile_tracker->AddString(index, entry.id(), str_id);
1304   }
1305 
1306   for (auto it = packet.mappings(); it; ++it) {
1307     protos::pbzero::ProfilePacket::Mapping::Decoder entry(it->data(),
1308                                                           it->size());
1309     HeapProfileTracker::SourceMapping src_mapping;
1310     src_mapping.build_id = entry.build_id();
1311     src_mapping.offset = entry.offset();
1312     src_mapping.start = entry.start();
1313     src_mapping.end = entry.end();
1314     src_mapping.load_bias = entry.load_bias();
1315     src_mapping.name_id = 0;
1316     for (auto path_string_id_it = entry.path_string_ids(); path_string_id_it;
1317          ++path_string_id_it)
1318       src_mapping.name_id = path_string_id_it->as_uint64();
1319     context_->heap_profile_tracker->AddMapping(index, entry.id(), src_mapping);
1320   }
1321 
1322   for (auto it = packet.frames(); it; ++it) {
1323     protos::pbzero::ProfilePacket::Frame::Decoder entry(it->data(), it->size());
1324     HeapProfileTracker::SourceFrame src_frame;
1325     src_frame.name_id = entry.function_name_id();
1326     src_frame.mapping_id = entry.mapping_id();
1327     src_frame.rel_pc = entry.rel_pc();
1328 
1329     context_->heap_profile_tracker->AddFrame(index, entry.id(), src_frame);
1330   }
1331 
1332   for (auto it = packet.callstacks(); it; ++it) {
1333     protos::pbzero::ProfilePacket::Callstack::Decoder entry(it->data(),
1334                                                             it->size());
1335     HeapProfileTracker::SourceCallstack src_callstack;
1336     for (auto frame_it = entry.frame_ids(); frame_it; ++frame_it)
1337       src_callstack.emplace_back(frame_it->as_uint64());
1338 
1339     context_->heap_profile_tracker->AddCallstack(index, entry.id(),
1340                                                  src_callstack);
1341   }
1342 
1343   for (auto it = packet.process_dumps(); it; ++it) {
1344     protos::pbzero::ProfilePacket::ProcessHeapSamples::Decoder entry(
1345         it->data(), it->size());
1346 
1347     int pid = static_cast<int>(entry.pid());
1348 
1349     if (entry.buffer_corrupted())
1350       context_->storage->IncrementIndexedStats(
1351           stats::heapprofd_buffer_corrupted, pid);
1352     if (entry.buffer_overran())
1353       context_->storage->IncrementIndexedStats(stats::heapprofd_buffer_overran,
1354                                                pid);
1355     if (entry.rejected_concurrent())
1356       context_->storage->IncrementIndexedStats(
1357           stats::heapprofd_rejected_concurrent, pid);
1358 
1359     for (auto sample_it = entry.samples(); sample_it; ++sample_it) {
1360       protos::pbzero::ProfilePacket::HeapSample::Decoder sample(
1361           sample_it->data(), sample_it->size());
1362 
1363       HeapProfileTracker::SourceAllocation src_allocation;
1364       src_allocation.pid = entry.pid();
1365       src_allocation.timestamp = sample.timestamp();
1366       src_allocation.callstack_id = sample.callstack_id();
1367       src_allocation.self_allocated = sample.self_allocated();
1368       src_allocation.self_freed = sample.self_freed();
1369       src_allocation.alloc_count = sample.alloc_count();
1370       src_allocation.free_count = sample.free_count();
1371 
1372       context_->heap_profile_tracker->StoreAllocation(index, src_allocation);
1373     }
1374   }
1375   if (!packet.continued()) {
1376     context_->heap_profile_tracker->ApplyAllAllocations();
1377     index++;
1378   }
1379 }
1380 
ParseSystemInfo(ConstBytes blob)1381 void ProtoTraceParser::ParseSystemInfo(ConstBytes blob) {
1382   protos::pbzero::SystemInfo::Decoder packet(blob.data, blob.size);
1383   if (packet.has_utsname()) {
1384     ConstBytes utsname_blob = packet.utsname();
1385     protos::pbzero::Utsname::Decoder utsname(utsname_blob.data,
1386                                              utsname_blob.size);
1387     base::StringView machine = utsname.machine();
1388     if (machine == "aarch64" || machine == "armv8l") {
1389       context_->syscall_tracker->SetArchitecture(kAarch64);
1390     } else if (machine == "x86_64") {
1391       context_->syscall_tracker->SetArchitecture(kX86_64);
1392     } else {
1393       PERFETTO_ELOG("Unknown architecture %s", machine.ToStdString().c_str());
1394     }
1395   }
1396 }
1397 
ParseTrackEvent(int64_t ts,int64_t,ProtoIncrementalState::PacketSequenceState * sequence_state,ConstBytes blob)1398 void ProtoTraceParser::ParseTrackEvent(
1399     int64_t ts,
1400     int64_t /*tts*/,
1401     ProtoIncrementalState::PacketSequenceState* sequence_state,
1402     ConstBytes blob) {
1403   protos::pbzero::TrackEvent::Decoder event(blob.data, blob.size);
1404 
1405   const auto legacy_event_blob = event.legacy_event();
1406   protos::pbzero::TrackEvent::LegacyEvent::Decoder legacy_event(
1407       legacy_event_blob.data, legacy_event_blob.size);
1408 
1409   // TODO(eseckler): This legacy event field will eventually be replaced by
1410   // fields in TrackEvent itself.
1411   if (PERFETTO_UNLIKELY(!legacy_event.has_phase())) {
1412     PERFETTO_ELOG("TrackEvent without phase");
1413     return;
1414   }
1415 
1416   ProcessTracker* procs = context_->process_tracker.get();
1417   TraceStorage* storage = context_->storage.get();
1418   SliceTracker* slice_tracker = context_->slice_tracker.get();
1419 
1420   uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
1421   uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
1422   if (legacy_event.has_pid_override())
1423     pid = static_cast<uint32_t>(legacy_event.pid_override());
1424   if (legacy_event.has_tid_override())
1425     tid = static_cast<uint32_t>(legacy_event.tid_override());
1426   UniqueTid utid = procs->UpdateThread(tid, pid);
1427 
1428   std::vector<uint32_t> category_iids;
1429   for (auto it = event.category_iids(); it; ++it) {
1430     category_iids.push_back(it->as_uint32());
1431   }
1432 
1433   StringId category_id = 0;
1434 
1435   // If there's a single category, we can avoid building a concatenated string.
1436   if (PERFETTO_LIKELY(category_iids.size() == 1)) {
1437     auto* map =
1438         sequence_state->GetInternedDataMap<protos::pbzero::EventCategory>();
1439     auto cat_view_it = map->find(category_iids[0]);
1440     if (cat_view_it == map->end()) {
1441       PERFETTO_ELOG("Could not find category interning entry for ID %u",
1442                     category_iids[0]);
1443     } else {
1444       // If the name is already in the pool, no need to decode it again.
1445       if (cat_view_it->second.storage_refs) {
1446         category_id = cat_view_it->second.storage_refs->name_id;
1447       } else {
1448         auto cat = cat_view_it->second.CreateDecoder();
1449         category_id = storage->InternString(cat.name());
1450         // Avoid having to decode & look up the name again in the future.
1451         cat_view_it->second.storage_refs =
1452             ProtoIncrementalState::StorageReferences<
1453                 protos::pbzero::EventCategory>{category_id};
1454       }
1455     }
1456   } else if (category_iids.size() > 1) {
1457     auto* map =
1458         sequence_state->GetInternedDataMap<protos::pbzero::EventCategory>();
1459     // We concatenate the category strings together since we currently only
1460     // support a single "cat" column.
1461     // TODO(eseckler): Support multi-category events in the table schema.
1462     std::string categories;
1463     for (uint32_t iid : category_iids) {
1464       auto cat_view_it = map->find(iid);
1465       if (cat_view_it == map->end()) {
1466         PERFETTO_ELOG("Could not find category interning entry for ID %u", iid);
1467         continue;
1468       }
1469       auto cat = cat_view_it->second.CreateDecoder();
1470       base::StringView name = cat.name();
1471       if (!categories.empty())
1472         categories.append(",");
1473       categories.append(name.data(), name.size());
1474     }
1475     if (!categories.empty())
1476       category_id = storage->InternString(base::StringView(categories));
1477   } else {
1478     PERFETTO_ELOG("TrackEvent without category");
1479   }
1480 
1481   StringId name_id = 0;
1482 
1483   if (PERFETTO_LIKELY(legacy_event.name_iid())) {
1484     auto* map =
1485         sequence_state->GetInternedDataMap<protos::pbzero::LegacyEventName>();
1486     auto name_view_it = map->find(legacy_event.name_iid());
1487     if (name_view_it == map->end()) {
1488       PERFETTO_ELOG("Could not find event name interning entry for ID %u",
1489                     legacy_event.name_iid());
1490     } else {
1491       // If the name is already in the pool, no need to decode it again.
1492       if (name_view_it->second.storage_refs) {
1493         name_id = name_view_it->second.storage_refs->name_id;
1494       } else {
1495         auto event_name = name_view_it->second.CreateDecoder();
1496         name_id = storage->InternString(event_name.name());
1497         // Avoid having to decode & look up the name again in the future.
1498         name_view_it->second.storage_refs =
1499             ProtoIncrementalState::StorageReferences<
1500                 protos::pbzero::LegacyEventName>{name_id};
1501       }
1502     }
1503   }
1504 
1505   // TODO(eseckler): Handle thread timestamp/duration, debug annotations, task
1506   // souce locations, legacy event attributes, ...
1507 
1508   int32_t phase = legacy_event.phase();
1509   switch (static_cast<char>(phase)) {
1510     case 'B': {  // TRACE_EVENT_PHASE_BEGIN.
1511       slice_tracker->Begin(ts, utid, category_id, name_id);
1512       break;
1513     }
1514     case 'E': {  // TRACE_EVENT_PHASE_END.
1515       slice_tracker->End(ts, utid, category_id, name_id);
1516       break;
1517     }
1518     case 'X': {  // TRACE_EVENT_PHASE_COMPLETE.
1519       auto duration_ns = legacy_event.duration_us() * 1000;
1520       if (duration_ns < 0)
1521         return;
1522       slice_tracker->Scoped(ts, utid, category_id, name_id, duration_ns);
1523       break;
1524     }
1525     case 'M': {  // TRACE_EVENT_PHASE_METADATA (process and thread names).
1526       // For now, we just compare the event name and assume there's a single
1527       // argument in these events with the name of the process/thread.
1528       // TODO(eseckler): Use names from process/thread descriptors instead.
1529       NullTermStringView event_name = storage->GetString(name_id);
1530       PERFETTO_DCHECK(event_name.data());
1531       if (strcmp(event_name.c_str(), "thread_name") == 0) {
1532         auto it = event.debug_annotations();
1533         if (!it)
1534           break;
1535         protos::pbzero::DebugAnnotation::Decoder annotation(it->data(),
1536                                                             it->size());
1537         auto thread_name = annotation.string_value();
1538         if (!thread_name.size)
1539           break;
1540         auto thread_name_id = context_->storage->InternString(thread_name);
1541         procs->UpdateThreadName(tid, thread_name_id);
1542       } else if (strcmp(event_name.c_str(), "process_name") == 0) {
1543         auto it = event.debug_annotations();
1544         if (!it)
1545           break;
1546         protos::pbzero::DebugAnnotation::Decoder annotation(it->data(),
1547                                                             it->size());
1548         auto process_name = annotation.string_value();
1549         if (!process_name.size)
1550           break;
1551         procs->UpdateProcess(pid, base::nullopt, process_name);
1552       }
1553       break;
1554     }
1555   }
1556 }
1557 
1558 }  // namespace trace_processor
1559 }  // namespace perfetto
1560