blob: c9528844bddd3d4643f1f74067b9543cd4f2b406 [file] [log] [blame]
Eric Secklerc165b872019-11-04 14:26:25 +00001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "src/trace_processor/importers/proto/heap_graph_module.h"
18
Lalit Maganti617deae2020-04-14 21:00:49 +010019#include "src/trace_processor/importers/common/process_tracker.h"
Eric Secklerc165b872019-11-04 14:26:25 +000020#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
Lalit Maganti7010b332020-02-07 10:51:15 +000021#include "src/trace_processor/storage/trace_storage.h"
Lalit Maganti0faddc42020-04-10 17:58:24 +010022#include "src/trace_processor/types/trace_processor_context.h"
Eric Secklerc165b872019-11-04 14:26:25 +000023
24#include "protos/perfetto/trace/profiling/heap_graph.pbzero.h"
25
26namespace perfetto {
27namespace trace_processor {
28
29namespace {
30
31const char* HeapGraphRootTypeToString(int32_t type) {
32 switch (type) {
33 case protos::pbzero::HeapGraphRoot::ROOT_UNKNOWN:
34 return "ROOT_UNKNOWN";
35 case protos::pbzero::HeapGraphRoot::ROOT_JNI_GLOBAL:
36 return "ROOT_JNI_GLOBAL";
37 case protos::pbzero::HeapGraphRoot::ROOT_JNI_LOCAL:
38 return "ROOT_JNI_LOCAL";
39 case protos::pbzero::HeapGraphRoot::ROOT_JAVA_FRAME:
40 return "ROOT_JAVA_FRAME";
41 case protos::pbzero::HeapGraphRoot::ROOT_NATIVE_STACK:
42 return "ROOT_NATIVE_STACK";
43 case protos::pbzero::HeapGraphRoot::ROOT_STICKY_CLASS:
44 return "ROOT_STICKY_CLASS";
45 case protos::pbzero::HeapGraphRoot::ROOT_THREAD_BLOCK:
46 return "ROOT_THREAD_BLOCK";
47 case protos::pbzero::HeapGraphRoot::ROOT_MONITOR_USED:
48 return "ROOT_MONITOR_USED";
49 case protos::pbzero::HeapGraphRoot::ROOT_THREAD_OBJECT:
50 return "ROOT_THREAD_OBJECT";
51 case protos::pbzero::HeapGraphRoot::ROOT_INTERNED_STRING:
52 return "ROOT_INTERNED_STRING";
53 case protos::pbzero::HeapGraphRoot::ROOT_FINALIZING:
54 return "ROOT_FINALIZING";
55 case protos::pbzero::HeapGraphRoot::ROOT_DEBUGGER:
56 return "ROOT_DEBUGGER";
57 case protos::pbzero::HeapGraphRoot::ROOT_REFERENCE_CLEANUP:
58 return "ROOT_REFERENCE_CLEANUP";
59 case protos::pbzero::HeapGraphRoot::ROOT_VM_INTERNAL:
60 return "ROOT_VM_INTERNAL";
61 case protos::pbzero::HeapGraphRoot::ROOT_JNI_MONITOR:
62 return "ROOT_JNI_MONITOR";
63 default:
64 return "ROOT_UNKNOWN";
65 }
66}
67
Florian Mayer905d1112019-11-15 16:47:03 +000068// Iterate over a repeated field of varints, independent of whether it is
69// packed or not.
70template <int32_t field_no, typename T, typename F>
71bool ForEachVarInt(const T& decoder, F fn) {
72 auto field = decoder.template at<field_no>();
73 bool parse_error = false;
74 if (field.type() == protozero::proto_utils::ProtoWireType::kLengthDelimited) {
75 // packed repeated
76 auto it = decoder.template GetPackedRepeated<
77 ::protozero::proto_utils::ProtoWireType::kVarInt, uint64_t>(
78 field_no, &parse_error);
79 for (; it; ++it)
80 fn(*it);
81 } else {
82 // non-packed repeated
83 auto it = decoder.template GetRepeated<uint64_t>(field_no);
84 for (; it; ++it)
85 fn(*it);
86 }
87 return parse_error;
88}
89
Eric Secklerc165b872019-11-04 14:26:25 +000090} // namespace
91
Mikhail Khokhlovddba3e62019-12-09 11:06:28 +000092using perfetto::protos::pbzero::TracePacket;
93
94HeapGraphModule::HeapGraphModule(TraceProcessorContext* context)
Lalit Maganti8a39fae2020-01-20 17:22:10 +000095 : context_(context) {
Mikhail Khokhlovddba3e62019-12-09 11:06:28 +000096 RegisterForField(TracePacket::kHeapGraphFieldNumber, context);
97 RegisterForField(TracePacket::kDeobfuscationMappingFieldNumber, context);
98}
99
100void HeapGraphModule::ParsePacket(
101 const protos::pbzero::TracePacket::Decoder& decoder,
102 const TimestampedTracePiece& ttp,
103 uint32_t field_id) {
104 switch (field_id) {
105 case TracePacket::kHeapGraphFieldNumber:
Florian Mayer1690fc52019-12-11 15:46:34 +0000106 ParseHeapGraph(decoder.trusted_packet_sequence_id(), ttp.timestamp,
107 decoder.heap_graph());
Mikhail Khokhlovddba3e62019-12-09 11:06:28 +0000108 return;
109 case TracePacket::kDeobfuscationMappingFieldNumber:
110 ParseDeobfuscationMapping(decoder.deobfuscation_mapping());
111 return;
112 }
113}
114
Florian Mayer1690fc52019-12-11 15:46:34 +0000115void HeapGraphModule::ParseHeapGraph(uint32_t seq_id,
116 int64_t ts,
117 protozero::ConstBytes blob) {
Lalit Maganti8a39fae2020-01-20 17:22:10 +0000118 auto* heap_graph_tracker = HeapGraphTracker::GetOrCreate(context_);
Eric Secklerc165b872019-11-04 14:26:25 +0000119 protos::pbzero::HeapGraph::Decoder heap_graph(blob.data, blob.size);
120 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
121 static_cast<uint32_t>(heap_graph.pid()));
Lalit Maganti8a39fae2020-01-20 17:22:10 +0000122 heap_graph_tracker->SetPacketIndex(seq_id, heap_graph.index());
Eric Secklerc165b872019-11-04 14:26:25 +0000123 for (auto it = heap_graph.objects(); it; ++it) {
124 protos::pbzero::HeapGraphObject::Decoder object(*it);
125 HeapGraphTracker::SourceObject obj;
126 obj.object_id = object.id();
127 obj.self_size = object.self_size();
128 obj.type_id = object.type_id();
Florian Mayer905d1112019-11-15 16:47:03 +0000129
130 std::vector<uint64_t> field_ids;
131 std::vector<uint64_t> object_ids;
132
133 bool parse_error = ForEachVarInt<
134 protos::pbzero::HeapGraphObject::kReferenceFieldIdFieldNumber>(
135 object, [&field_ids](uint64_t value) { field_ids.push_back(value); });
136
137 if (!parse_error) {
138 parse_error = ForEachVarInt<
139 protos::pbzero::HeapGraphObject::kReferenceObjectIdFieldNumber>(
140 object,
141 [&object_ids](uint64_t value) { object_ids.push_back(value); });
Florian Mayera9669012019-11-15 14:53:22 +0000142 }
Florian Mayeracb44472019-11-15 16:46:03 +0000143
Florian Mayer905d1112019-11-15 16:47:03 +0000144 if (parse_error) {
145 context_->storage->IncrementIndexedStats(
146 stats::heap_graph_malformed_packet, static_cast<int>(upid));
147 break;
148 }
149 if (field_ids.size() != object_ids.size()) {
150 context_->storage->IncrementIndexedStats(
151 stats::heap_graph_malformed_packet, static_cast<int>(upid));
Florian Mayeracb44472019-11-15 16:46:03 +0000152 continue;
153 }
Florian Mayer905d1112019-11-15 16:47:03 +0000154 for (size_t i = 0; i < field_ids.size(); ++i) {
155 HeapGraphTracker::SourceObject::Reference ref;
156 ref.field_name_id = field_ids[i];
157 ref.owned_object_id = object_ids[i];
158 obj.references.emplace_back(std::move(ref));
159 }
Lalit Maganti8a39fae2020-01-20 17:22:10 +0000160 heap_graph_tracker->AddObject(seq_id, upid, ts, std::move(obj));
Eric Secklerc165b872019-11-04 14:26:25 +0000161 }
Florian Mayer3ef10d42020-03-19 14:45:07 +0100162 for (auto it = heap_graph.types(); it; ++it) {
163 protos::pbzero::HeapGraphType::Decoder entry(*it);
164 const char* str = reinterpret_cast<const char*>(entry.class_name().data);
165 auto str_view = base::StringView(str, entry.class_name().size);
166
167 heap_graph_tracker->AddInternedType(
168 seq_id, entry.id(), context_->storage->InternString(str_view),
169 entry.location_id());
170 }
Eric Secklerc165b872019-11-04 14:26:25 +0000171 for (auto it = heap_graph.field_names(); it; ++it) {
172 protos::pbzero::InternedString::Decoder entry(*it);
173 const char* str = reinterpret_cast<const char*>(entry.str().data);
174 auto str_view = base::StringView(str, entry.str().size);
175
Florian Mayer0a4a05d2020-02-06 17:58:17 +0000176 heap_graph_tracker->AddInternedFieldName(seq_id, entry.iid(), str_view);
Eric Secklerc165b872019-11-04 14:26:25 +0000177 }
Florian Mayer3ef10d42020-03-19 14:45:07 +0100178 for (auto it = heap_graph.location_names(); it; ++it) {
179 protos::pbzero::InternedString::Decoder entry(*it);
180 const char* str = reinterpret_cast<const char*>(entry.str().data);
181 auto str_view = base::StringView(str, entry.str().size);
182
183 heap_graph_tracker->AddInternedLocationName(
184 seq_id, entry.iid(), context_->storage->InternString(str_view));
185 }
Eric Secklerc165b872019-11-04 14:26:25 +0000186 for (auto it = heap_graph.roots(); it; ++it) {
187 protos::pbzero::HeapGraphRoot::Decoder entry(*it);
188 const char* str = HeapGraphRootTypeToString(entry.root_type());
189 auto str_view = base::StringView(str);
190
191 HeapGraphTracker::SourceRoot src_root;
192 src_root.root_type = context_->storage->InternString(str_view);
Florian Mayer905d1112019-11-15 16:47:03 +0000193 bool parse_error =
194 ForEachVarInt<protos::pbzero::HeapGraphRoot::kObjectIdsFieldNumber>(
195 entry, [&src_root](uint64_t value) {
196 src_root.object_ids.emplace_back(value);
197 });
198 if (parse_error) {
199 context_->storage->IncrementIndexedStats(
200 stats::heap_graph_malformed_packet, static_cast<int>(upid));
201 break;
202 }
Lalit Maganti8a39fae2020-01-20 17:22:10 +0000203 heap_graph_tracker->AddRoot(seq_id, upid, ts, std::move(src_root));
Eric Secklerc165b872019-11-04 14:26:25 +0000204 }
205 if (!heap_graph.continued()) {
Lalit Maganti8a39fae2020-01-20 17:22:10 +0000206 heap_graph_tracker->FinalizeProfile(seq_id);
Eric Secklerc165b872019-11-04 14:26:25 +0000207 }
208}
209
Florian Mayer38408922020-04-09 20:55:24 +0200210void HeapGraphModule::DeobfuscateClass(
211 base::Optional<StringPool::Id> package_name_id,
212 StringPool::Id obfuscated_class_name_id,
213 const protos::pbzero::ObfuscatedClass::Decoder& cls) {
214 auto* heap_graph_tracker = HeapGraphTracker::GetOrCreate(context_);
215 const std::vector<tables::HeapGraphClassTable::Id>* cls_objects =
216 heap_graph_tracker->RowsForType(package_name_id,
217 obfuscated_class_name_id);
218
219 if (cls_objects) {
220 heap_graph_tracker->AddDeobfuscationMapping(
221 package_name_id, obfuscated_class_name_id,
222 context_->storage->InternString(
223 base::StringView(cls.deobfuscated_name())));
224
225 for (tables::HeapGraphClassTable::Id id : *cls_objects) {
226 uint32_t row =
227 *context_->storage->heap_graph_class_table().id().IndexOf(id);
228 const StringPool::Id obfuscated_type_name =
229 context_->storage->heap_graph_class_table().name()[row];
230 StringPool::Id deobfuscated_type_name =
231 heap_graph_tracker->MaybeDeobfuscate(package_name_id,
232 obfuscated_type_name);
233 PERFETTO_CHECK(!deobfuscated_type_name.is_null());
234 context_->storage->mutable_heap_graph_class_table()
235 ->mutable_deobfuscated_name()
236 ->Set(row, deobfuscated_type_name);
237 }
238 } else {
239 PERFETTO_DLOG("Class %s not found",
240 cls.obfuscated_name().ToStdString().c_str());
241 }
242}
243
Florian Mayere0f2b0e2019-11-26 14:20:36 +0000244void HeapGraphModule::ParseDeobfuscationMapping(protozero::ConstBytes blob) {
Lalit Maganti8a39fae2020-01-20 17:22:10 +0000245 auto* heap_graph_tracker = HeapGraphTracker::GetOrCreate(context_);
Florian Mayere0f2b0e2019-11-26 14:20:36 +0000246 protos::pbzero::DeobfuscationMapping::Decoder deobfuscation_mapping(
247 blob.data, blob.size);
Florian Mayer38408922020-04-09 20:55:24 +0200248 base::Optional<StringPool::Id> package_name_id;
249 if (deobfuscation_mapping.package_name().size > 0) {
250 package_name_id = context_->storage->string_pool().GetId(
251 deobfuscation_mapping.package_name());
252 }
253
Florian Mayere0f2b0e2019-11-26 14:20:36 +0000254 for (auto class_it = deobfuscation_mapping.obfuscated_classes(); class_it;
255 ++class_it) {
256 protos::pbzero::ObfuscatedClass::Decoder cls(*class_it);
257 auto obfuscated_class_name_id =
258 context_->storage->string_pool().GetId(cls.obfuscated_name());
259 if (!obfuscated_class_name_id) {
260 PERFETTO_DLOG("Class string %s not found",
261 cls.obfuscated_name().ToStdString().c_str());
262 } else {
Florian Mayer38408922020-04-09 20:55:24 +0200263 // TODO(b/153552977): Remove this work-around for legacy traces.
264 // For traces without location information, deobfuscate all matching
265 // classes.
266 DeobfuscateClass(base::nullopt, *obfuscated_class_name_id, cls);
267 if (package_name_id) {
268 DeobfuscateClass(package_name_id, *obfuscated_class_name_id, cls);
Florian Mayere0f2b0e2019-11-26 14:20:36 +0000269 }
270 }
271 for (auto member_it = cls.obfuscated_members(); member_it; ++member_it) {
272 protos::pbzero::ObfuscatedMember::Decoder member(*member_it);
273
274 std::string merged_obfuscated = cls.obfuscated_name().ToStdString() +
275 "." +
276 member.obfuscated_name().ToStdString();
Florian Mayere6a829e2020-02-06 16:07:28 +0000277 std::string merged_deobfuscated;
278 std::string member_deobfuscated_name =
Florian Mayere0f2b0e2019-11-26 14:20:36 +0000279 member.deobfuscated_name().ToStdString();
Florian Mayere6a829e2020-02-06 16:07:28 +0000280 if (member_deobfuscated_name.find('.') == std::string::npos) {
281 // Name relative to class.
282 merged_deobfuscated = cls.deobfuscated_name().ToStdString() + "." +
283 member_deobfuscated_name;
284 } else {
285 // Fully qualified name.
286 merged_deobfuscated = std::move(member_deobfuscated_name);
287 }
Florian Mayere0f2b0e2019-11-26 14:20:36 +0000288
289 auto obfuscated_field_name_id = context_->storage->string_pool().GetId(
290 base::StringView(merged_obfuscated));
291 if (!obfuscated_field_name_id) {
292 PERFETTO_DLOG("Field string %s not found", merged_obfuscated.c_str());
293 continue;
294 }
295
296 const std::vector<int64_t>* field_references =
Lalit Maganti8a39fae2020-01-20 17:22:10 +0000297 heap_graph_tracker->RowsForField(*obfuscated_field_name_id);
Florian Mayere0f2b0e2019-11-26 14:20:36 +0000298 if (field_references) {
299 auto interned_deobfuscated_name = context_->storage->InternString(
300 base::StringView(merged_deobfuscated));
301 for (int64_t row : *field_references) {
302 context_->storage->mutable_heap_graph_reference_table()
303 ->mutable_deobfuscated_field_name()
304 ->Set(static_cast<uint32_t>(row), interned_deobfuscated_name);
305 }
306 } else {
307 PERFETTO_DLOG("Field %s not found", merged_obfuscated.c_str());
308 }
309 }
310 }
311}
312
Florian Mayer0b6655d2020-02-14 09:09:21 -0500313void HeapGraphModule::NotifyEndOfFile() {
314 auto* heap_graph_tracker = HeapGraphTracker::GetOrCreate(context_);
315 heap_graph_tracker->NotifyEndOfFile();
316}
317
Eric Secklerc165b872019-11-04 14:26:25 +0000318} // namespace trace_processor
319} // namespace perfetto