• 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 #include <optional>
19 #include <string>
20 
21 #include "perfetto/base/logging.h"
22 #include "perfetto/ext/base/flat_hash_map.h"
23 #include "perfetto/ext/base/string_utils.h"
24 #include "perfetto/ext/base/string_view.h"
25 #include "src/trace_processor/importers/common/args_translation_table.h"
26 #include "src/trace_processor/importers/common/clock_tracker.h"
27 #include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
28 #include "src/trace_processor/importers/common/event_tracker.h"
29 #include "src/trace_processor/importers/common/mapping_tracker.h"
30 #include "src/trace_processor/importers/common/process_tracker.h"
31 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
32 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
33 #include "src/trace_processor/importers/proto/perf_sample_tracker.h"
34 #include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
35 #include "src/trace_processor/importers/proto/profile_packet_utils.h"
36 #include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
37 #include "src/trace_processor/sorter/trace_sorter.h"
38 #include "src/trace_processor/storage/stats.h"
39 #include "src/trace_processor/storage/trace_storage.h"
40 #include "src/trace_processor/tables/profiler_tables_py.h"
41 #include "src/trace_processor/types/trace_processor_context.h"
42 #include "src/trace_processor/util/build_id.h"
43 #include "src/trace_processor/util/profiler_util.h"
44 
45 #include "protos/perfetto/common/builtin_clock.pbzero.h"
46 #include "protos/perfetto/common/perf_events.pbzero.h"
47 #include "protos/perfetto/trace/profiling/deobfuscation.pbzero.h"
48 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
49 #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
50 #include "protos/perfetto/trace/profiling/smaps.pbzero.h"
51 
52 namespace perfetto {
53 namespace trace_processor {
54 
55 using perfetto::protos::pbzero::TracePacket;
56 using protozero::ConstBytes;
57 
ProfileModule(TraceProcessorContext * context)58 ProfileModule::ProfileModule(TraceProcessorContext* context)
59     : context_(context) {
60   RegisterForField(TracePacket::kStreamingProfilePacketFieldNumber, context);
61   RegisterForField(TracePacket::kPerfSampleFieldNumber, context);
62   RegisterForField(TracePacket::kProfilePacketFieldNumber, context);
63   RegisterForField(TracePacket::kModuleSymbolsFieldNumber, context);
64   // note: deobfuscation mappings also handled by HeapGraphModule.
65   RegisterForField(TracePacket::kDeobfuscationMappingFieldNumber, context);
66   RegisterForField(TracePacket::kSmapsPacketFieldNumber, context);
67 }
68 
69 ProfileModule::~ProfileModule() = default;
70 
TokenizePacket(const TracePacket::Decoder & decoder,TraceBlobView * packet,int64_t,RefPtr<PacketSequenceStateGeneration> state,uint32_t field_id)71 ModuleResult ProfileModule::TokenizePacket(
72     const TracePacket::Decoder& decoder,
73     TraceBlobView* packet,
74     int64_t /*packet_timestamp*/,
75     RefPtr<PacketSequenceStateGeneration> state,
76     uint32_t field_id) {
77   switch (field_id) {
78     case TracePacket::kStreamingProfilePacketFieldNumber:
79       return TokenizeStreamingProfilePacket(std::move(state), packet,
80                                             decoder.streaming_profile_packet());
81   }
82   return ModuleResult::Ignored();
83 }
84 
ParseTracePacketData(const protos::pbzero::TracePacket::Decoder & decoder,int64_t ts,const TracePacketData & data,uint32_t field_id)85 void ProfileModule::ParseTracePacketData(
86     const protos::pbzero::TracePacket::Decoder& decoder,
87     int64_t ts,
88     const TracePacketData& data,
89     uint32_t field_id) {
90   switch (field_id) {
91     case TracePacket::kStreamingProfilePacketFieldNumber:
92       ParseStreamingProfilePacket(ts, data.sequence_state.get(),
93                                   decoder.streaming_profile_packet());
94       return;
95     case TracePacket::kPerfSampleFieldNumber:
96       ParsePerfSample(ts, data.sequence_state.get(), decoder);
97       return;
98     case TracePacket::kProfilePacketFieldNumber:
99       ParseProfilePacket(ts, data.sequence_state.get(),
100                          decoder.profile_packet());
101       return;
102     case TracePacket::kModuleSymbolsFieldNumber:
103       ParseModuleSymbols(decoder.module_symbols());
104       return;
105     case TracePacket::kDeobfuscationMappingFieldNumber:
106       ParseDeobfuscationMapping(ts, data.sequence_state.get(),
107                                 decoder.trusted_packet_sequence_id(),
108                                 decoder.deobfuscation_mapping());
109       return;
110     case TracePacket::kSmapsPacketFieldNumber:
111       ParseSmapsPacket(ts, decoder.smaps_packet());
112       return;
113   }
114 }
115 
TokenizeStreamingProfilePacket(RefPtr<PacketSequenceStateGeneration> sequence_state,TraceBlobView * packet,ConstBytes streaming_profile_packet)116 ModuleResult ProfileModule::TokenizeStreamingProfilePacket(
117     RefPtr<PacketSequenceStateGeneration> sequence_state,
118     TraceBlobView* packet,
119     ConstBytes streaming_profile_packet) {
120   protos::pbzero::StreamingProfilePacket::Decoder decoder(
121       streaming_profile_packet.data, streaming_profile_packet.size);
122 
123   // We have to resolve the reference timestamp of a StreamingProfilePacket
124   // during tokenization. If we did this during parsing instead, the
125   // tokenization of a subsequent ThreadDescriptor with a new reference
126   // timestamp would cause us to later calculate timestamps based on the wrong
127   // reference value during parsing. Since StreamingProfilePackets only need to
128   // be sorted correctly with respect to process/thread metadata events (so that
129   // pid/tid are resolved correctly during parsing), we forward the packet as a
130   // whole through the sorter, using the "root" timestamp of the packet, i.e.
131   // the current timestamp of the packet sequence.
132   auto packet_ts =
133       sequence_state->IncrementAndGetTrackEventTimeNs(/*delta_ns=*/0);
134   base::StatusOr<int64_t> trace_ts = context_->clock_tracker->ToTraceTime(
135       protos::pbzero::BUILTIN_CLOCK_MONOTONIC, packet_ts);
136   if (trace_ts.ok())
137     packet_ts = *trace_ts;
138 
139   // Increment the sequence's timestamp by all deltas.
140   for (auto timestamp_it = decoder.timestamp_delta_us(); timestamp_it;
141        ++timestamp_it) {
142     sequence_state->IncrementAndGetTrackEventTimeNs(*timestamp_it * 1000);
143   }
144 
145   context_->sorter->PushTracePacket(packet_ts, std::move(sequence_state),
146                                     std::move(*packet), context_->machine_id());
147   return ModuleResult::Handled();
148 }
149 
ParseStreamingProfilePacket(int64_t timestamp,PacketSequenceStateGeneration * sequence_state,ConstBytes streaming_profile_packet)150 void ProfileModule::ParseStreamingProfilePacket(
151     int64_t timestamp,
152     PacketSequenceStateGeneration* sequence_state,
153     ConstBytes streaming_profile_packet) {
154   protos::pbzero::StreamingProfilePacket::Decoder packet(
155       streaming_profile_packet.data, streaming_profile_packet.size);
156 
157   ProcessTracker* procs = context_->process_tracker.get();
158   TraceStorage* storage = context_->storage.get();
159   StackProfileSequenceState& stack_profile_sequence_state =
160       *sequence_state->GetCustomState<StackProfileSequenceState>();
161 
162   uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
163   uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
164   const UniqueTid utid = procs->UpdateThread(tid, pid);
165   const UniquePid upid = procs->GetOrCreateProcess(pid);
166 
167   // Iterate through timestamps and callstacks simultaneously.
168   auto timestamp_it = packet.timestamp_delta_us();
169   for (auto callstack_it = packet.callstack_iid(); callstack_it;
170        ++callstack_it, ++timestamp_it) {
171     if (!timestamp_it) {
172       context_->storage->IncrementStats(stats::stackprofile_parser_error);
173       PERFETTO_ELOG(
174           "StreamingProfilePacket has less callstack IDs than timestamps!");
175       break;
176     }
177 
178     auto opt_cs_id =
179         stack_profile_sequence_state.FindOrInsertCallstack(upid, *callstack_it);
180     if (!opt_cs_id) {
181       context_->storage->IncrementStats(stats::stackprofile_parser_error);
182       continue;
183     }
184 
185     // Resolve the delta timestamps based on the packet's root timestamp.
186     timestamp += *timestamp_it * 1000;
187 
188     tables::CpuProfileStackSampleTable::Row sample_row{
189         timestamp, *opt_cs_id, utid, packet.process_priority()};
190     storage->mutable_cpu_profile_stack_sample_table()->Insert(sample_row);
191   }
192 }
193 
ParsePerfSample(int64_t ts,PacketSequenceStateGeneration * sequence_state,const TracePacket::Decoder & decoder)194 void ProfileModule::ParsePerfSample(
195     int64_t ts,
196     PacketSequenceStateGeneration* sequence_state,
197     const TracePacket::Decoder& decoder) {
198   using PerfSample = protos::pbzero::PerfSample;
199   const auto& sample_raw = decoder.perf_sample();
200   PerfSample::Decoder sample(sample_raw.data, sample_raw.size);
201 
202   uint32_t seq_id = decoder.trusted_packet_sequence_id();
203   PerfSampleTracker::SamplingStreamInfo sampling_stream =
204       context_->perf_sample_tracker->GetSamplingStreamInfo(
205           seq_id, sample.cpu(), sequence_state->GetTracePacketDefaults());
206 
207   // Not a sample, but an indication of data loss in the ring buffer shared with
208   // the kernel.
209   if (sample.kernel_records_lost() > 0) {
210     PERFETTO_DCHECK(sample.pid() == 0);
211 
212     context_->storage->IncrementIndexedStats(
213         stats::perf_cpu_lost_records, static_cast<int>(sample.cpu()),
214         static_cast<int64_t>(sample.kernel_records_lost()));
215     return;
216   }
217 
218   // Not a sample, but an event from the producer.
219   // TODO(rsavitski): this stat is indexed by the session id, but the older
220   // stats (see above) aren't. The indexing is relevant if a trace contains more
221   // than one profiling data source. So the older stats should be changed to
222   // being indexed as well.
223   if (sample.has_producer_event()) {
224     PerfSample::ProducerEvent::Decoder producer_event(sample.producer_event());
225     if (producer_event.source_stop_reason() ==
226         PerfSample::ProducerEvent::PROFILER_STOP_GUARDRAIL) {
227       context_->storage->SetIndexedStats(
228           stats::perf_guardrail_stop_ts,
229           static_cast<int>(sampling_stream.perf_session_id.value), ts);
230     }
231     return;
232   }
233 
234   // Sample has incomplete stack sampling payload (not necessarily an error).
235   if (sample.has_sample_skipped_reason()) {
236     switch (sample.sample_skipped_reason()) {
237       case (PerfSample::PROFILER_SKIP_NOT_IN_SCOPE):
238         // WAI, we're recording per-cpu but the sampled process was not in
239         // config's scope. The counter part of the sample is still relevant.
240         break;
241       case (PerfSample::PROFILER_SKIP_READ_STAGE):
242       case (PerfSample::PROFILER_SKIP_UNWIND_STAGE):
243         context_->storage->IncrementStats(stats::perf_samples_skipped);
244         break;
245       case (PerfSample::PROFILER_SKIP_UNWIND_ENQUEUE):
246         context_->storage->IncrementStats(stats::perf_samples_skipped_dataloss);
247         break;
248       default:
249         break;
250     }
251   }
252 
253   // Populate the |perf_sample| table with everything except the recorded
254   // counter values, which go to |counter|.
255   context_->event_tracker->PushCounter(
256       ts, static_cast<double>(sample.timebase_count()),
257       sampling_stream.timebase_track_id);
258 
259   if (sample.has_follower_counts()) {
260     auto track_it = sampling_stream.follower_track_ids.begin();
261     auto track_end = sampling_stream.follower_track_ids.end();
262     for (auto it = sample.follower_counts(); it && track_it != track_end;
263          ++it, ++track_it) {
264       context_->event_tracker->PushCounter(ts, static_cast<double>(*it),
265                                            *track_it);
266     }
267   }
268 
269   const UniqueTid utid =
270       context_->process_tracker->UpdateThread(sample.tid(), sample.pid());
271   const UniquePid upid =
272       context_->process_tracker->GetOrCreateProcess(sample.pid());
273 
274   std::optional<CallsiteId> cs_id;
275   StackProfileSequenceState& stack_profile_sequence_state =
276       *sequence_state->GetCustomState<StackProfileSequenceState>();
277   if (sample.has_callstack_iid()) {
278     uint64_t callstack_iid = sample.callstack_iid();
279     cs_id =
280         stack_profile_sequence_state.FindOrInsertCallstack(upid, callstack_iid);
281   }
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   std::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,ConstBytes blob)303 void ProfileModule::ParseProfilePacket(
304     int64_t ts,
305     PacketSequenceStateGeneration* sequence_state,
306     ConstBytes blob) {
307   ProfilePacketSequenceState& profile_packet_sequence_state =
308       *sequence_state->GetCustomState<ProfilePacketSequenceState>();
309   protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
310   profile_packet_sequence_state.SetProfilePacketIndex(packet.index());
311 
312   for (auto it = packet.strings(); it; ++it) {
313     protos::pbzero::InternedString::Decoder entry(*it);
314     const char* str = reinterpret_cast<const char*>(entry.str().data);
315     auto str_view = base::StringView(str, entry.str().size);
316     profile_packet_sequence_state.AddString(entry.iid(), str_view);
317   }
318 
319   for (auto it = packet.mappings(); it; ++it) {
320     protos::pbzero::Mapping::Decoder entry(*it);
321     profile_packet_sequence_state.AddMapping(
322         entry.iid(), ProfilePacketUtils::MakeSourceMapping(entry));
323   }
324 
325   for (auto it = packet.frames(); it; ++it) {
326     protos::pbzero::Frame::Decoder entry(*it);
327     profile_packet_sequence_state.AddFrame(
328         entry.iid(), ProfilePacketUtils::MakeSourceFrame(entry));
329   }
330 
331   for (auto it = packet.callstacks(); it; ++it) {
332     protos::pbzero::Callstack::Decoder entry(*it);
333     profile_packet_sequence_state.AddCallstack(
334         entry.iid(), ProfilePacketUtils::MakeSourceCallstack(entry));
335   }
336 
337   for (auto it = packet.process_dumps(); it; ++it) {
338     protos::pbzero::ProfilePacket::ProcessHeapSamples::Decoder entry(*it);
339 
340     base::StatusOr<int64_t> maybe_timestamp =
341         context_->clock_tracker->ToTraceTime(
342             protos::pbzero::BUILTIN_CLOCK_MONOTONIC_COARSE,
343             static_cast<int64_t>(entry.timestamp()));
344 
345     // ToTraceTime() increments the clock_sync_failure error stat in this case.
346     if (!maybe_timestamp.ok())
347       continue;
348 
349     int64_t timestamp = *maybe_timestamp;
350 
351     int pid = static_cast<int>(entry.pid());
352     context_->storage->SetIndexedStats(stats::heapprofd_last_profile_timestamp,
353                                        pid, ts);
354 
355     if (entry.disconnected())
356       context_->storage->IncrementIndexedStats(
357           stats::heapprofd_client_disconnected, pid);
358     if (entry.buffer_corrupted())
359       context_->storage->IncrementIndexedStats(
360           stats::heapprofd_buffer_corrupted, pid);
361     if (entry.buffer_overran() ||
362         entry.client_error() ==
363             protos::pbzero::ProfilePacket::ProcessHeapSamples::
364                 CLIENT_ERROR_HIT_TIMEOUT) {
365       context_->storage->IncrementIndexedStats(stats::heapprofd_buffer_overran,
366                                                pid);
367     }
368     if (entry.client_error()) {
369       context_->storage->SetIndexedStats(stats::heapprofd_client_error, pid,
370                                          entry.client_error());
371     }
372     if (entry.rejected_concurrent())
373       context_->storage->IncrementIndexedStats(
374           stats::heapprofd_rejected_concurrent, pid);
375     if (entry.hit_guardrail())
376       context_->storage->IncrementIndexedStats(stats::heapprofd_hit_guardrail,
377                                                pid);
378     if (entry.orig_sampling_interval_bytes()) {
379       context_->storage->SetIndexedStats(
380           stats::heapprofd_sampling_interval_adjusted, pid,
381           static_cast<int64_t>(entry.sampling_interval_bytes()) -
382               static_cast<int64_t>(entry.orig_sampling_interval_bytes()));
383     }
384 
385     protos::pbzero::ProfilePacket::ProcessStats::Decoder stats(entry.stats());
386     context_->storage->IncrementIndexedStats(
387         stats::heapprofd_unwind_time_us, static_cast<int>(entry.pid()),
388         static_cast<int64_t>(stats.total_unwinding_time_us()));
389     context_->storage->IncrementIndexedStats(
390         stats::heapprofd_unwind_samples, static_cast<int>(entry.pid()),
391         static_cast<int64_t>(stats.heap_samples()));
392     context_->storage->IncrementIndexedStats(
393         stats::heapprofd_client_spinlock_blocked, static_cast<int>(entry.pid()),
394         static_cast<int64_t>(stats.client_spinlock_blocked_us()));
395 
396     // orig_sampling_interval_bytes was introduced slightly after a bug with
397     // self_max_count was fixed in the producer. We use this as a proxy
398     // whether or not we are getting this data from a fixed producer or not.
399     bool trustworthy_max_count = entry.orig_sampling_interval_bytes() > 0;
400 
401     for (auto sample_it = entry.samples(); sample_it; ++sample_it) {
402       protos::pbzero::ProfilePacket::HeapSample::Decoder sample(*sample_it);
403 
404       ProfilePacketSequenceState::SourceAllocation src_allocation;
405       src_allocation.pid = entry.pid();
406       if (entry.heap_name().size != 0) {
407         src_allocation.heap_name =
408             context_->storage->InternString(entry.heap_name());
409       } else {
410         // After aosp/1348782 there should be a heap name associated with all
411         // allocations - absence of one is likely a bug (for traces captured
412         // in older builds, this was the native heap profiler (libc.malloc)).
413         src_allocation.heap_name = context_->storage->InternString("unknown");
414       }
415       src_allocation.timestamp = timestamp;
416       src_allocation.callstack_id = sample.callstack_id();
417       if (sample.has_self_max()) {
418         src_allocation.self_allocated = sample.self_max();
419         if (trustworthy_max_count)
420           src_allocation.alloc_count = sample.self_max_count();
421       } else {
422         src_allocation.self_allocated = sample.self_allocated();
423         src_allocation.self_freed = sample.self_freed();
424         src_allocation.alloc_count = sample.alloc_count();
425         src_allocation.free_count = sample.free_count();
426       }
427 
428       profile_packet_sequence_state.StoreAllocation(src_allocation);
429     }
430   }
431   if (!packet.continued()) {
432     profile_packet_sequence_state.FinalizeProfile();
433   }
434 }
435 
ParseModuleSymbols(ConstBytes blob)436 void ProfileModule::ParseModuleSymbols(ConstBytes blob) {
437   protos::pbzero::ModuleSymbols::Decoder module_symbols(blob.data, blob.size);
438   BuildId build_id = BuildId::FromRaw(module_symbols.build_id());
439 
440   auto mappings =
441       context_->mapping_tracker->FindMappings(module_symbols.path(), build_id);
442   if (mappings.empty()) {
443     context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
444     return;
445   }
446   for (auto addr_it = module_symbols.address_symbols(); addr_it; ++addr_it) {
447     protos::pbzero::AddressSymbols::Decoder address_symbols(*addr_it);
448 
449     uint32_t symbol_set_id = context_->storage->symbol_table().row_count();
450 
451     bool has_lines = false;
452     // Taking the last (i.e. the least interned) location if there're several.
453     ArgsTranslationTable::SourceLocation last_location;
454     for (auto line_it = address_symbols.lines(); line_it; ++line_it) {
455       protos::pbzero::Line::Decoder line(*line_it);
456       auto file_name = line.source_file_name();
457       context_->storage->mutable_symbol_table()->Insert(
458           {symbol_set_id, context_->storage->InternString(line.function_name()),
459            file_name.size == 0 ? kNullStringId
460                                : context_->storage->InternString(file_name),
461            line.has_line_number() && file_name.size != 0
462                ? std::make_optional(line.line_number())
463                : std::nullopt});
464       last_location = ArgsTranslationTable::SourceLocation{
465           file_name.ToStdString(), line.function_name().ToStdString(),
466           line.line_number()};
467       has_lines = true;
468     }
469     if (!has_lines) {
470       continue;
471     }
472     bool frame_found = false;
473     for (VirtualMemoryMapping* mapping : mappings) {
474       context_->args_translation_table->AddNativeSymbolTranslationRule(
475           mapping->mapping_id(), address_symbols.address(), last_location);
476       std::vector<FrameId> frame_ids =
477           mapping->FindFrameIds(address_symbols.address());
478 
479       for (const FrameId frame_id : frame_ids) {
480         auto* frames = context_->storage->mutable_stack_profile_frame_table();
481         auto rr = *frames->FindById(frame_id);
482         rr.set_symbol_set_id(symbol_set_id);
483         frame_found = true;
484       }
485     }
486 
487     if (!frame_found) {
488       context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
489       continue;
490     }
491   }
492 }
493 
ParseDeobfuscationMapping(int64_t,PacketSequenceStateGeneration *,uint32_t,ConstBytes blob)494 void ProfileModule::ParseDeobfuscationMapping(int64_t,
495                                               PacketSequenceStateGeneration*,
496                                               uint32_t /* seq_id */,
497                                               ConstBytes blob) {
498   DeobfuscationMappingTable deobfuscation_mapping_table;
499   protos::pbzero::DeobfuscationMapping::Decoder deobfuscation_mapping(
500       blob.data, blob.size);
501   if (deobfuscation_mapping.package_name().size == 0)
502     return;
503 
504   auto opt_package_name_id = context_->storage->string_pool().GetId(
505       deobfuscation_mapping.package_name());
506   auto opt_memfd_id = context_->storage->string_pool().GetId("memfd");
507   if (!opt_package_name_id && !opt_memfd_id)
508     return;
509 
510   for (auto class_it = deobfuscation_mapping.obfuscated_classes(); class_it;
511        ++class_it) {
512     protos::pbzero::ObfuscatedClass::Decoder cls(*class_it);
513     base::FlatHashMap<StringId, StringId> obfuscated_to_deobfuscated_members;
514     for (auto member_it = cls.obfuscated_methods(); member_it; ++member_it) {
515       protos::pbzero::ObfuscatedMember::Decoder member(*member_it);
516       std::string merged_obfuscated = cls.obfuscated_name().ToStdString() +
517                                       "." +
518                                       member.obfuscated_name().ToStdString();
519       auto merged_obfuscated_id = context_->storage->string_pool().GetId(
520           base::StringView(merged_obfuscated));
521       if (!merged_obfuscated_id)
522         continue;
523       std::string merged_deobfuscated =
524           FullyQualifiedDeobfuscatedName(cls, member);
525 
526       std::vector<tables::StackProfileFrameTable::Id> frames;
527       if (opt_package_name_id) {
528         const std::vector<tables::StackProfileFrameTable::Id> pkg_frames =
529             context_->stack_profile_tracker->JavaFramesForName(
530                 {*merged_obfuscated_id, *opt_package_name_id});
531         frames.insert(frames.end(), pkg_frames.begin(), pkg_frames.end());
532       }
533       if (opt_memfd_id) {
534         const std::vector<tables::StackProfileFrameTable::Id> memfd_frames =
535             context_->stack_profile_tracker->JavaFramesForName(
536                 {*merged_obfuscated_id, *opt_memfd_id});
537         frames.insert(frames.end(), memfd_frames.begin(), memfd_frames.end());
538       }
539 
540       for (tables::StackProfileFrameTable::Id frame_id : frames) {
541         auto* frames_tbl =
542             context_->storage->mutable_stack_profile_frame_table();
543         auto rr = *frames_tbl->FindById(frame_id);
544         rr.set_deobfuscated_name(context_->storage->InternString(
545             base::StringView(merged_deobfuscated)));
546       }
547       obfuscated_to_deobfuscated_members[context_->storage->InternString(
548           member.obfuscated_name())] =
549           context_->storage->InternString(member.deobfuscated_name());
550     }
551     // Members can contain a class name (e.g "ClassA.FunctionF")
552     deobfuscation_mapping_table.AddClassTranslation(
553         DeobfuscationMappingTable::PackageId{
554             deobfuscation_mapping.package_name().ToStdString(),
555             deobfuscation_mapping.version_code()},
556         context_->storage->InternString(cls.obfuscated_name()),
557         context_->storage->InternString(cls.deobfuscated_name()),
558         std::move(obfuscated_to_deobfuscated_members));
559   }
560   context_->args_translation_table->AddDeobfuscationMappingTable(
561       std::move(deobfuscation_mapping_table));
562 }
563 
ParseSmapsPacket(int64_t ts,ConstBytes blob)564 void ProfileModule::ParseSmapsPacket(int64_t ts, ConstBytes blob) {
565   protos::pbzero::SmapsPacket::Decoder sp(blob.data, blob.size);
566   auto upid = context_->process_tracker->GetOrCreateProcess(sp.pid());
567 
568   for (auto it = sp.entries(); it; ++it) {
569     protos::pbzero::SmapsEntry::Decoder e(*it);
570     context_->storage->mutable_profiler_smaps_table()->Insert(
571         {upid, ts, context_->storage->InternString(e.path()),
572          static_cast<int64_t>(e.size_kb()),
573          static_cast<int64_t>(e.private_dirty_kb()),
574          static_cast<int64_t>(e.swap_kb()),
575          context_->storage->InternString(e.file_name()),
576          static_cast<int64_t>(e.start_address()),
577          static_cast<int64_t>(e.module_timestamp()),
578          context_->storage->InternString(e.module_debugid()),
579          context_->storage->InternString(e.module_debug_path()),
580          static_cast<int32_t>(e.protection_flags()),
581          static_cast<int64_t>(e.private_clean_resident_kb()),
582          static_cast<int64_t>(e.shared_dirty_resident_kb()),
583          static_cast<int64_t>(e.shared_clean_resident_kb()),
584          static_cast<int64_t>(e.locked_kb()),
585          static_cast<int64_t>(e.proportional_resident_kb())});
586   }
587 }
588 
NotifyEndOfFile()589 void ProfileModule::NotifyEndOfFile() {
590   for (auto it = context_->storage->stack_profile_mapping_table().IterateRows();
591        it; ++it) {
592     NullTermStringView path = context_->storage->GetString(it.name());
593     NullTermStringView build_id = context_->storage->GetString(it.build_id());
594 
595     if (path.StartsWith("/data/local/tmp/") && build_id.empty()) {
596       context_->storage->IncrementStats(
597           stats::symbolization_tmp_build_id_not_found);
598     }
599   }
600 }
601 
602 }  // namespace trace_processor
603 }  // namespace perfetto
604