• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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/profile_module.h"
18 
19 #include "perfetto/base/logging.h"
20 #include "perfetto/ext/base/string_utils.h"
21 #include "src/trace_processor/importers/common/clock_tracker.h"
22 #include "src/trace_processor/importers/common/event_tracker.h"
23 #include "src/trace_processor/importers/common/process_tracker.h"
24 #include "src/trace_processor/importers/proto/heap_profile_tracker.h"
25 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
26 #include "src/trace_processor/importers/proto/perf_sample_tracker.h"
27 #include "src/trace_processor/importers/proto/profile_packet_utils.h"
28 #include "src/trace_processor/importers/proto/profiler_util.h"
29 #include "src/trace_processor/importers/proto/stack_profile_tracker.h"
30 #include "src/trace_processor/storage/trace_storage.h"
31 #include "src/trace_processor/tables/profiler_tables.h"
32 #include "src/trace_processor/timestamped_trace_piece.h"
33 #include "src/trace_processor/trace_sorter.h"
34 #include "src/trace_processor/types/trace_processor_context.h"
35 
36 #include "protos/perfetto/common/builtin_clock.pbzero.h"
37 #include "protos/perfetto/common/perf_events.pbzero.h"
38 #include "protos/perfetto/trace/profiling/deobfuscation.pbzero.h"
39 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
40 #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
41 #include "protos/perfetto/trace/profiling/smaps.pbzero.h"
42 
43 namespace perfetto {
44 namespace trace_processor {
45 
46 using perfetto::protos::pbzero::TracePacket;
47 using protozero::ConstBytes;
48 
ProfileModule(TraceProcessorContext * context)49 ProfileModule::ProfileModule(TraceProcessorContext* context)
50     : context_(context) {
51   RegisterForField(TracePacket::kStreamingProfilePacketFieldNumber, context);
52   RegisterForField(TracePacket::kPerfSampleFieldNumber, context);
53   RegisterForField(TracePacket::kProfilePacketFieldNumber, context);
54   RegisterForField(TracePacket::kModuleSymbolsFieldNumber, context);
55   // note: deobfuscation mappings also handled by HeapGraphModule.
56   RegisterForField(TracePacket::kDeobfuscationMappingFieldNumber, context);
57   RegisterForField(TracePacket::kSmapsPacketFieldNumber, context);
58 }
59 
60 ProfileModule::~ProfileModule() = default;
61 
TokenizePacket(const TracePacket::Decoder & decoder,TraceBlobView * packet,int64_t,PacketSequenceState * state,uint32_t field_id)62 ModuleResult ProfileModule::TokenizePacket(const TracePacket::Decoder& decoder,
63                                            TraceBlobView* packet,
64                                            int64_t /*packet_timestamp*/,
65                                            PacketSequenceState* state,
66                                            uint32_t field_id) {
67   switch (field_id) {
68     case TracePacket::kStreamingProfilePacketFieldNumber:
69       return TokenizeStreamingProfilePacket(state, packet,
70                                             decoder.streaming_profile_packet());
71   }
72   return ModuleResult::Ignored();
73 }
74 
ParsePacket(const TracePacket::Decoder & decoder,const TimestampedTracePiece & ttp,uint32_t field_id)75 void ProfileModule::ParsePacket(const TracePacket::Decoder& decoder,
76                                 const TimestampedTracePiece& ttp,
77                                 uint32_t field_id) {
78   switch (field_id) {
79     case TracePacket::kStreamingProfilePacketFieldNumber:
80       PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
81       ParseStreamingProfilePacket(ttp.timestamp,
82                                   ttp.packet_data.sequence_state.get(),
83                                   decoder.streaming_profile_packet());
84       return;
85     case TracePacket::kPerfSampleFieldNumber:
86       PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
87       ParsePerfSample(ttp.timestamp, ttp.packet_data.sequence_state.get(),
88                       decoder);
89       return;
90     case TracePacket::kProfilePacketFieldNumber:
91       PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
92       ParseProfilePacket(ttp.timestamp, ttp.packet_data.sequence_state.get(),
93                          decoder.trusted_packet_sequence_id(),
94                          decoder.profile_packet());
95       return;
96     case TracePacket::kModuleSymbolsFieldNumber:
97       PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
98       ParseModuleSymbols(decoder.module_symbols());
99       return;
100     case TracePacket::kDeobfuscationMappingFieldNumber:
101       PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
102       ParseDeobfuscationMapping(ttp.timestamp,
103                                 ttp.packet_data.sequence_state.get(),
104                                 decoder.trusted_packet_sequence_id(),
105                                 decoder.deobfuscation_mapping());
106       return;
107     case TracePacket::kSmapsPacketFieldNumber:
108       PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
109       ParseSmapsPacket(ttp.timestamp, decoder.smaps_packet());
110       return;
111   }
112 }
113 
TokenizeStreamingProfilePacket(PacketSequenceState * sequence_state,TraceBlobView * packet,ConstBytes streaming_profile_packet)114 ModuleResult ProfileModule::TokenizeStreamingProfilePacket(
115     PacketSequenceState* sequence_state,
116     TraceBlobView* packet,
117     ConstBytes streaming_profile_packet) {
118   protos::pbzero::StreamingProfilePacket::Decoder decoder(
119       streaming_profile_packet.data, streaming_profile_packet.size);
120 
121   // We have to resolve the reference timestamp of a StreamingProfilePacket
122   // during tokenization. If we did this during parsing instead, the
123   // tokenization of a subsequent ThreadDescriptor with a new reference
124   // timestamp would cause us to later calculate timestamps based on the wrong
125   // reference value during parsing. Since StreamingProfilePackets only need to
126   // be sorted correctly with respect to process/thread metadata events (so that
127   // pid/tid are resolved correctly during parsing), we forward the packet as a
128   // whole through the sorter, using the "root" timestamp of the packet, i.e.
129   // the current timestamp of the packet sequence.
130   auto packet_ts =
131       sequence_state->IncrementAndGetTrackEventTimeNs(/*delta_ns=*/0);
132   auto trace_ts = context_->clock_tracker->ToTraceTime(
133       protos::pbzero::BUILTIN_CLOCK_MONOTONIC, packet_ts);
134   if (trace_ts)
135     packet_ts = *trace_ts;
136 
137   // Increment the sequence's timestamp by all deltas.
138   for (auto timestamp_it = decoder.timestamp_delta_us(); timestamp_it;
139        ++timestamp_it) {
140     sequence_state->IncrementAndGetTrackEventTimeNs(*timestamp_it * 1000);
141   }
142 
143   context_->sorter->PushTracePacket(packet_ts, sequence_state,
144                                     std::move(*packet));
145   return ModuleResult::Handled();
146 }
147 
ParseStreamingProfilePacket(int64_t timestamp,PacketSequenceStateGeneration * sequence_state,ConstBytes streaming_profile_packet)148 void ProfileModule::ParseStreamingProfilePacket(
149     int64_t timestamp,
150     PacketSequenceStateGeneration* sequence_state,
151     ConstBytes streaming_profile_packet) {
152   protos::pbzero::StreamingProfilePacket::Decoder packet(
153       streaming_profile_packet.data, streaming_profile_packet.size);
154 
155   ProcessTracker* procs = context_->process_tracker.get();
156   TraceStorage* storage = context_->storage.get();
157   SequenceStackProfileTracker& sequence_stack_profile_tracker =
158       sequence_state->state()->sequence_stack_profile_tracker();
159   ProfilePacketInternLookup intern_lookup(sequence_state);
160 
161   uint32_t pid = static_cast<uint32_t>(sequence_state->state()->pid());
162   uint32_t tid = static_cast<uint32_t>(sequence_state->state()->tid());
163   UniqueTid utid = procs->UpdateThread(tid, pid);
164 
165   // Iterate through timestamps and callstacks simultaneously.
166   auto timestamp_it = packet.timestamp_delta_us();
167   for (auto callstack_it = packet.callstack_iid(); callstack_it;
168        ++callstack_it, ++timestamp_it) {
169     if (!timestamp_it) {
170       context_->storage->IncrementStats(stats::stackprofile_parser_error);
171       PERFETTO_ELOG(
172           "StreamingProfilePacket has less callstack IDs than timestamps!");
173       break;
174     }
175 
176     auto opt_cs_id = sequence_stack_profile_tracker.FindOrInsertCallstack(
177         *callstack_it, &intern_lookup);
178     if (!opt_cs_id) {
179       context_->storage->IncrementStats(stats::stackprofile_parser_error);
180       continue;
181     }
182 
183     // Resolve the delta timestamps based on the packet's root timestamp.
184     timestamp += *timestamp_it * 1000;
185 
186     tables::CpuProfileStackSampleTable::Row sample_row{
187         timestamp, *opt_cs_id, utid, packet.process_priority()};
188     storage->mutable_cpu_profile_stack_sample_table()->Insert(sample_row);
189   }
190 }
191 
ParsePerfSample(int64_t ts,PacketSequenceStateGeneration * sequence_state,const TracePacket::Decoder & decoder)192 void ProfileModule::ParsePerfSample(
193     int64_t ts,
194     PacketSequenceStateGeneration* sequence_state,
195     const TracePacket::Decoder& decoder) {
196   using PerfSample = protos::pbzero::PerfSample;
197   const auto& sample_raw = decoder.perf_sample();
198   PerfSample::Decoder sample(sample_raw.data, sample_raw.size);
199 
200   uint32_t seq_id = decoder.trusted_packet_sequence_id();
201   PerfSampleTracker::SamplingStreamInfo sampling_stream =
202       context_->perf_sample_tracker->GetSamplingStreamInfo(
203           seq_id, sample.cpu(), sequence_state->GetTracePacketDefaults());
204 
205   // Not a sample, but an indication of data loss in the ring buffer shared with
206   // the kernel.
207   if (sample.kernel_records_lost() > 0) {
208     PERFETTO_DCHECK(sample.pid() == 0);
209 
210     context_->storage->IncrementIndexedStats(
211         stats::perf_cpu_lost_records, static_cast<int>(sample.cpu()),
212         static_cast<int64_t>(sample.kernel_records_lost()));
213     return;
214   }
215 
216   // Sample that looked relevant for the tracing session, but had to be skipped.
217   // Either we failed to look up the procfs file descriptors necessary for
218   // remote stack unwinding (not unexpected in most cases), or the unwind queue
219   // was out of capacity (producer lost data on its own).
220   if (sample.has_sample_skipped_reason()) {
221     context_->storage->IncrementStats(stats::perf_samples_skipped);
222 
223     if (sample.sample_skipped_reason() ==
224         PerfSample::PROFILER_SKIP_UNWIND_ENQUEUE)
225       context_->storage->IncrementStats(stats::perf_samples_skipped_dataloss);
226 
227     return;
228   }
229 
230   // Not a sample, but an event from the producer.
231   // TODO(rsavitski): this stat is indexed by the session id, but the older
232   // stats (see above) aren't. The indexing is relevant if a trace contains more
233   // than one profiling data source. So the older stats should be changed to
234   // being indexed as well.
235   if (sample.has_producer_event()) {
236     PerfSample::ProducerEvent::Decoder producer_event(sample.producer_event());
237     if (producer_event.source_stop_reason() ==
238         PerfSample::ProducerEvent::PROFILER_STOP_GUARDRAIL) {
239       context_->storage->SetIndexedStats(
240           stats::perf_guardrail_stop_ts,
241           static_cast<int>(sampling_stream.perf_session_id), ts);
242     }
243     return;
244   }
245 
246   // Proper sample, populate the |perf_sample| table with everything except the
247   // recorded counter values, which go to |counter|.
248   context_->event_tracker->PushCounter(
249       ts, static_cast<double>(sample.timebase_count()),
250       sampling_stream.timebase_track_id);
251 
252   SequenceStackProfileTracker& stack_tracker =
253       sequence_state->state()->sequence_stack_profile_tracker();
254   ProfilePacketInternLookup intern_lookup(sequence_state);
255   uint64_t callstack_iid = sample.callstack_iid();
256   base::Optional<CallsiteId> cs_id =
257       stack_tracker.FindOrInsertCallstack(callstack_iid, &intern_lookup);
258 
259   // A failed lookup of the interned callstack can mean either:
260   // (a) This is a counter-only profile without callstacks. Due to an
261   //     implementation quirk, these packets still set callstack_iid
262   //     corresponding to a callstack with no frames. To reliably identify this
263   //     case (without resorting to config parsing) we further need to rely on
264   //     the fact that the implementation (callstack_trie.h) always assigns this
265   //     callstack the id "1". Such callstacks should not occur outside of
266   //     counter-only profiles, as there should always be at least a synthetic
267   //     error frame if the unwinding completely failed.
268   // (b) This is a ring-buffer profile where some of the referenced internings
269   //     have been overwritten, and the build predates perf_sample_defaults and
270   //     SEQ_NEEDS_INCREMENTAL_STATE sequence flag in perf_sample packets.
271   //     Such packets should be discarded.
272   if (!cs_id && callstack_iid != 1) {
273     PERFETTO_DLOG("Discarding perf_sample since callstack_iid [%" PRIu64
274                   "] references a missing/partially lost interning according "
275                   "to stack_profile_tracker",
276                   callstack_iid);
277     return;
278   }
279 
280   UniqueTid utid =
281       context_->process_tracker->UpdateThread(sample.tid(), sample.pid());
282 
283   using protos::pbzero::Profiling;
284   TraceStorage* storage = context_->storage.get();
285 
286   auto cpu_mode = static_cast<Profiling::CpuMode>(sample.cpu_mode());
287   StringPool::Id cpu_mode_id =
288       storage->InternString(ProfilePacketUtils::StringifyCpuMode(cpu_mode));
289 
290   base::Optional<StringPool::Id> unwind_error_id;
291   if (sample.has_unwind_error()) {
292     auto unwind_error =
293         static_cast<Profiling::StackUnwindError>(sample.unwind_error());
294     unwind_error_id = storage->InternString(
295         ProfilePacketUtils::StringifyStackUnwindError(unwind_error));
296   }
297   tables::PerfSampleTable::Row sample_row(ts, utid, sample.cpu(), cpu_mode_id,
298                                           cs_id, unwind_error_id,
299                                           sampling_stream.perf_session_id);
300   context_->storage->mutable_perf_sample_table()->Insert(sample_row);
301 }
302 
ParseProfilePacket(int64_t ts,PacketSequenceStateGeneration * sequence_state,uint32_t seq_id,ConstBytes blob)303 void ProfileModule::ParseProfilePacket(
304     int64_t ts,
305     PacketSequenceStateGeneration* sequence_state,
306     uint32_t seq_id,
307     ConstBytes blob) {
308   protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
309   context_->heap_profile_tracker->SetProfilePacketIndex(seq_id, packet.index());
310 
311   for (auto it = packet.strings(); it; ++it) {
312     protos::pbzero::InternedString::Decoder entry(*it);
313 
314     const char* str = reinterpret_cast<const char*>(entry.str().data);
315     auto str_view = base::StringView(str, entry.str().size);
316     sequence_state->state()->sequence_stack_profile_tracker().AddString(
317         entry.iid(), str_view);
318   }
319 
320   for (auto it = packet.mappings(); it; ++it) {
321     protos::pbzero::Mapping::Decoder entry(*it);
322     SequenceStackProfileTracker::SourceMapping src_mapping =
323         ProfilePacketUtils::MakeSourceMapping(entry);
324     sequence_state->state()->sequence_stack_profile_tracker().AddMapping(
325         entry.iid(), src_mapping);
326   }
327 
328   for (auto it = packet.frames(); it; ++it) {
329     protos::pbzero::Frame::Decoder entry(*it);
330     SequenceStackProfileTracker::SourceFrame src_frame =
331         ProfilePacketUtils::MakeSourceFrame(entry);
332     sequence_state->state()->sequence_stack_profile_tracker().AddFrame(
333         entry.iid(), src_frame);
334   }
335 
336   for (auto it = packet.callstacks(); it; ++it) {
337     protos::pbzero::Callstack::Decoder entry(*it);
338     SequenceStackProfileTracker::SourceCallstack src_callstack =
339         ProfilePacketUtils::MakeSourceCallstack(entry);
340     sequence_state->state()->sequence_stack_profile_tracker().AddCallstack(
341         entry.iid(), src_callstack);
342   }
343 
344   for (auto it = packet.process_dumps(); it; ++it) {
345     protos::pbzero::ProfilePacket::ProcessHeapSamples::Decoder entry(*it);
346 
347     auto maybe_timestamp = context_->clock_tracker->ToTraceTime(
348         protos::pbzero::BUILTIN_CLOCK_MONOTONIC_COARSE,
349         static_cast<int64_t>(entry.timestamp()));
350 
351     // ToTraceTime() increments the clock_sync_failure error stat in this case.
352     if (!maybe_timestamp)
353       continue;
354 
355     int64_t timestamp = *maybe_timestamp;
356 
357     int pid = static_cast<int>(entry.pid());
358     context_->storage->SetIndexedStats(stats::heapprofd_last_profile_timestamp,
359                                        pid, ts);
360 
361     if (entry.disconnected())
362       context_->storage->IncrementIndexedStats(
363           stats::heapprofd_client_disconnected, pid);
364     if (entry.buffer_corrupted())
365       context_->storage->IncrementIndexedStats(
366           stats::heapprofd_buffer_corrupted, pid);
367     if (entry.buffer_overran() ||
368         entry.client_error() ==
369             protos::pbzero::ProfilePacket::ProcessHeapSamples::
370                 CLIENT_ERROR_HIT_TIMEOUT) {
371       context_->storage->IncrementIndexedStats(stats::heapprofd_buffer_overran,
372                                                pid);
373     }
374     if (entry.client_error()) {
375       context_->storage->SetIndexedStats(stats::heapprofd_client_error, pid,
376                                          entry.client_error());
377     }
378     if (entry.rejected_concurrent())
379       context_->storage->IncrementIndexedStats(
380           stats::heapprofd_rejected_concurrent, pid);
381     if (entry.hit_guardrail())
382       context_->storage->IncrementIndexedStats(stats::heapprofd_hit_guardrail,
383                                                pid);
384     if (entry.orig_sampling_interval_bytes()) {
385       context_->storage->SetIndexedStats(
386           stats::heapprofd_sampling_interval_adjusted, pid,
387           static_cast<int64_t>(entry.sampling_interval_bytes()) -
388               static_cast<int64_t>(entry.orig_sampling_interval_bytes()));
389     }
390 
391     protos::pbzero::ProfilePacket::ProcessStats::Decoder stats(entry.stats());
392     context_->storage->IncrementIndexedStats(
393         stats::heapprofd_unwind_time_us, static_cast<int>(entry.pid()),
394         static_cast<int64_t>(stats.total_unwinding_time_us()));
395     context_->storage->IncrementIndexedStats(
396         stats::heapprofd_unwind_samples, static_cast<int>(entry.pid()),
397         static_cast<int64_t>(stats.heap_samples()));
398     context_->storage->IncrementIndexedStats(
399         stats::heapprofd_client_spinlock_blocked, static_cast<int>(entry.pid()),
400         static_cast<int64_t>(stats.client_spinlock_blocked_us()));
401 
402     // orig_sampling_interval_bytes was introduced slightly after a bug with
403     // self_max_count was fixed in the producer. We use this as a proxy
404     // whether or not we are getting this data from a fixed producer or not.
405     bool trustworthy_max_count = entry.orig_sampling_interval_bytes() > 0;
406 
407     for (auto sample_it = entry.samples(); sample_it; ++sample_it) {
408       protos::pbzero::ProfilePacket::HeapSample::Decoder sample(*sample_it);
409 
410       HeapProfileTracker::SourceAllocation src_allocation;
411       src_allocation.pid = entry.pid();
412       if (entry.heap_name().size != 0) {
413         src_allocation.heap_name =
414             context_->storage->InternString(entry.heap_name());
415       } else {
416         src_allocation.heap_name = context_->storage->InternString("malloc");
417       }
418       src_allocation.timestamp = timestamp;
419       src_allocation.callstack_id = sample.callstack_id();
420       if (sample.has_self_max()) {
421         src_allocation.self_allocated = sample.self_max();
422         if (trustworthy_max_count)
423           src_allocation.alloc_count = sample.self_max_count();
424       } else {
425         src_allocation.self_allocated = sample.self_allocated();
426         src_allocation.self_freed = sample.self_freed();
427         src_allocation.alloc_count = sample.alloc_count();
428         src_allocation.free_count = sample.free_count();
429       }
430 
431       context_->heap_profile_tracker->StoreAllocation(seq_id, src_allocation);
432     }
433   }
434   if (!packet.continued()) {
435     PERFETTO_CHECK(sequence_state);
436     ProfilePacketInternLookup intern_lookup(sequence_state);
437     context_->heap_profile_tracker->FinalizeProfile(
438         seq_id, &sequence_state->state()->sequence_stack_profile_tracker(),
439         &intern_lookup);
440   }
441 }
442 
ParseModuleSymbols(ConstBytes blob)443 void ProfileModule::ParseModuleSymbols(ConstBytes blob) {
444   protos::pbzero::ModuleSymbols::Decoder module_symbols(blob.data, blob.size);
445   StringId build_id;
446   // TODO(b/148109467): Remove workaround once all active Chrome versions
447   // write raw bytes instead of a string as build_id.
448   if (module_symbols.build_id().size == 33) {
449     build_id = context_->storage->InternString(module_symbols.build_id());
450   } else {
451     build_id = context_->storage->InternString(base::StringView(base::ToHex(
452         module_symbols.build_id().data, module_symbols.build_id().size)));
453   }
454 
455   auto mapping_ids = context_->global_stack_profile_tracker->FindMappingRow(
456       context_->storage->InternString(module_symbols.path()), build_id);
457   if (mapping_ids.empty()) {
458     context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
459     return;
460   }
461   for (auto addr_it = module_symbols.address_symbols(); addr_it; ++addr_it) {
462     protos::pbzero::AddressSymbols::Decoder address_symbols(*addr_it);
463 
464     uint32_t symbol_set_id = context_->storage->symbol_table().row_count();
465 
466     bool has_lines = false;
467     for (auto line_it = address_symbols.lines(); line_it; ++line_it) {
468       protos::pbzero::Line::Decoder line(*line_it);
469       context_->storage->mutable_symbol_table()->Insert(
470           {symbol_set_id, context_->storage->InternString(line.function_name()),
471            context_->storage->InternString(line.source_file_name()),
472            line.line_number()});
473       has_lines = true;
474     }
475     if (!has_lines) {
476       continue;
477     }
478     bool frame_found = false;
479     for (MappingId mapping_id : mapping_ids) {
480       std::vector<FrameId> frame_ids =
481           context_->global_stack_profile_tracker->FindFrameIds(
482               mapping_id, address_symbols.address());
483 
484       for (const FrameId frame_id : frame_ids) {
485         auto* frames = context_->storage->mutable_stack_profile_frame_table();
486         uint32_t frame_row = *frames->id().IndexOf(frame_id);
487         frames->mutable_symbol_set_id()->Set(frame_row, symbol_set_id);
488         frame_found = true;
489       }
490     }
491 
492     if (!frame_found) {
493       context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
494       continue;
495     }
496   }
497 }
498 
ParseDeobfuscationMapping(int64_t,PacketSequenceStateGeneration *,uint32_t,ConstBytes blob)499 void ProfileModule::ParseDeobfuscationMapping(int64_t,
500                                               PacketSequenceStateGeneration*,
501                                               uint32_t /* seq_id */,
502                                               ConstBytes blob) {
503   protos::pbzero::DeobfuscationMapping::Decoder deobfuscation_mapping(
504       blob.data, blob.size);
505   if (deobfuscation_mapping.package_name().size == 0)
506     return;
507 
508   auto opt_package_name_id = context_->storage->string_pool().GetId(
509       deobfuscation_mapping.package_name());
510   auto opt_memfd_id = context_->storage->string_pool().GetId("memfd");
511   if (!opt_package_name_id && !opt_memfd_id)
512     return;
513 
514   for (auto class_it = deobfuscation_mapping.obfuscated_classes(); class_it;
515        ++class_it) {
516     protos::pbzero::ObfuscatedClass::Decoder cls(*class_it);
517     for (auto member_it = cls.obfuscated_methods(); member_it; ++member_it) {
518       protos::pbzero::ObfuscatedMember::Decoder member(*member_it);
519       std::string merged_obfuscated = cls.obfuscated_name().ToStdString() +
520                                       "." +
521                                       member.obfuscated_name().ToStdString();
522       auto merged_obfuscated_id = context_->storage->string_pool().GetId(
523           base::StringView(merged_obfuscated));
524       if (!merged_obfuscated_id)
525         continue;
526       std::string merged_deobfuscated =
527           FullyQualifiedDeobfuscatedName(cls, member);
528 
529       std::vector<tables::StackProfileFrameTable::Id> frames;
530       if (opt_package_name_id) {
531         const std::vector<tables::StackProfileFrameTable::Id>* pkg_frames =
532             context_->global_stack_profile_tracker->JavaFramesForName(
533                 {*merged_obfuscated_id, *opt_package_name_id});
534         if (pkg_frames) {
535           frames.insert(frames.end(), pkg_frames->begin(), pkg_frames->end());
536         }
537       }
538       if (opt_memfd_id) {
539         const std::vector<tables::StackProfileFrameTable::Id>* memfd_frames =
540             context_->global_stack_profile_tracker->JavaFramesForName(
541                 {*merged_obfuscated_id, *opt_memfd_id});
542         if (memfd_frames) {
543           frames.insert(frames.end(), memfd_frames->begin(),
544                         memfd_frames->end());
545         }
546       }
547 
548       for (tables::StackProfileFrameTable::Id frame_id : frames) {
549         auto* frames_tbl =
550             context_->storage->mutable_stack_profile_frame_table();
551         frames_tbl->mutable_deobfuscated_name()->Set(
552             *frames_tbl->id().IndexOf(frame_id),
553             context_->storage->InternString(
554                 base::StringView(merged_deobfuscated)));
555       }
556     }
557   }
558 }
559 
ParseSmapsPacket(int64_t ts,ConstBytes blob)560 void ProfileModule::ParseSmapsPacket(int64_t ts, ConstBytes blob) {
561   protos::pbzero::SmapsPacket::Decoder sp(blob.data, blob.size);
562   auto upid = context_->process_tracker->GetOrCreateProcess(sp.pid());
563 
564   for (auto it = sp.entries(); it; ++it) {
565     protos::pbzero::SmapsEntry::Decoder e(*it);
566     context_->storage->mutable_profiler_smaps_table()->Insert(
567         {upid, ts, context_->storage->InternString(e.path()),
568          static_cast<int64_t>(e.size_kb()),
569          static_cast<int64_t>(e.private_dirty_kb()),
570          static_cast<int64_t>(e.swap_kb()),
571          context_->storage->InternString(e.file_name()),
572          static_cast<int64_t>(e.start_address()),
573          static_cast<int64_t>(e.module_timestamp()),
574          context_->storage->InternString(e.module_debugid()),
575          context_->storage->InternString(e.module_debug_path()),
576          static_cast<int32_t>(e.protection_flags()),
577          static_cast<int64_t>(e.private_clean_resident_kb()),
578          static_cast<int64_t>(e.shared_dirty_resident_kb()),
579          static_cast<int64_t>(e.shared_clean_resident_kb()),
580          static_cast<int64_t>(e.locked_kb()),
581          static_cast<int64_t>(e.proportional_resident_kb())});
582   }
583 }
584 
585 }  // namespace trace_processor
586 }  // namespace perfetto
587