1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "perfetto_hprof"
18 
19 #include "perfetto_hprof.h"
20 
21 #include <android-base/logging.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <sched.h>
25 #include <signal.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30 #include <sys/wait.h>
31 #include <thread>
32 #include <time.h>
33 
34 #include <type_traits>
35 
36 #include "gc/heap-visit-objects-inl.h"
37 #include "gc/heap.h"
38 #include "gc/scoped_gc_critical_section.h"
39 #include "mirror/object-refvisitor-inl.h"
40 #include "nativehelper/scoped_local_ref.h"
41 #include "perfetto/profiling/normalize.h"
42 #include "perfetto/profiling/parse_smaps.h"
43 #include "perfetto/trace/interned_data/interned_data.pbzero.h"
44 #include "perfetto/trace/profiling/heap_graph.pbzero.h"
45 #include "perfetto/trace/profiling/profile_common.pbzero.h"
46 #include "perfetto/trace/profiling/smaps.pbzero.h"
47 #include "perfetto/config/profiling/java_hprof_config.pbzero.h"
48 #include "perfetto/protozero/packed_repeated_fields.h"
49 #include "perfetto/tracing.h"
50 #include "runtime-inl.h"
51 #include "runtime_callbacks.h"
52 #include "scoped_thread_state_change-inl.h"
53 #include "thread_list.h"
54 #include "well_known_classes.h"
55 #include "dex/descriptors_names.h"
56 
57 // There are three threads involved in this:
58 // * listener thread: this is idle in the background when this plugin gets loaded, and waits
59 //   for data on on g_signal_pipe_fds.
60 // * signal thread: an arbitrary thread that handles the signal and writes data to
61 //   g_signal_pipe_fds.
62 // * perfetto producer thread: once the signal is received, the app forks. In the newly forked
63 //   child, the Perfetto Client API spawns a thread to communicate with traced.
64 
65 namespace perfetto_hprof {
66 
67 constexpr int kJavaHeapprofdSignal = __SIGRTMIN + 6;
68 constexpr time_t kWatchdogTimeoutSec = 120;
69 // This needs to be lower than the maximum acceptable chunk size, because this
70 // is checked *before* writing another submessage. We conservatively assume
71 // submessages can be up to 100k here for a 500k chunk size.
72 // DropBox has a 500k chunk limit, and each chunk needs to parse as a proto.
73 constexpr uint32_t kPacketSizeThreshold = 400000;
74 constexpr char kByte[1] = {'x'};
GetStateMutex()75 static art::Mutex& GetStateMutex() {
76   static art::Mutex state_mutex("perfetto_hprof_state_mutex", art::LockLevel::kGenericBottomLock);
77   return state_mutex;
78 }
79 
GetStateCV()80 static art::ConditionVariable& GetStateCV() {
81   static art::ConditionVariable state_cv("perfetto_hprof_state_cv", GetStateMutex());
82   return state_cv;
83 }
84 
85 static State g_state = State::kUninitialized;
86 
87 // Pipe to signal from the signal handler into a worker thread that handles the
88 // dump requests.
89 int g_signal_pipe_fds[2];
90 static struct sigaction g_orig_act = {};
91 
92 template <typename T>
FindOrAppend(std::map<T,uint64_t> * m,const T & s)93 uint64_t FindOrAppend(std::map<T, uint64_t>* m, const T& s) {
94   auto it = m->find(s);
95   if (it == m->end()) {
96     std::tie(it, std::ignore) = m->emplace(s, m->size());
97   }
98   return it->second;
99 }
100 
ArmWatchdogOrDie()101 void ArmWatchdogOrDie() {
102   timer_t timerid{};
103   struct sigevent sev {};
104   sev.sigev_notify = SIGEV_SIGNAL;
105   sev.sigev_signo = SIGKILL;
106 
107   if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1) {
108     // This only gets called in the child, so we can fatal without impacting
109     // the app.
110     PLOG(FATAL) << "failed to create watchdog timer";
111   }
112 
113   struct itimerspec its {};
114   its.it_value.tv_sec = kWatchdogTimeoutSec;
115 
116   if (timer_settime(timerid, 0, &its, nullptr) == -1) {
117     // This only gets called in the child, so we can fatal without impacting
118     // the app.
119     PLOG(FATAL) << "failed to arm watchdog timer";
120   }
121 }
122 
StartsWith(const std::string & str,const std::string & prefix)123 bool StartsWith(const std::string& str, const std::string& prefix) {
124   return str.compare(0, prefix.length(), prefix) == 0;
125 }
126 
127 // Sample entries that match one of the following
128 // start with /system/
129 // start with /vendor/
130 // start with /data/app/
131 // contains "extracted in memory from Y", where Y matches any of the above
ShouldSampleSmapsEntry(const perfetto::profiling::SmapsEntry & e)132 bool ShouldSampleSmapsEntry(const perfetto::profiling::SmapsEntry& e) {
133   if (StartsWith(e.pathname, "/system/") || StartsWith(e.pathname, "/vendor/") ||
134       StartsWith(e.pathname, "/data/app/")) {
135     return true;
136   }
137   if (StartsWith(e.pathname, "[anon:")) {
138     if (e.pathname.find("extracted in memory from /system/") != std::string::npos) {
139       return true;
140     }
141     if (e.pathname.find("extracted in memory from /vendor/") != std::string::npos) {
142       return true;
143     }
144     if (e.pathname.find("extracted in memory from /data/app/") != std::string::npos) {
145       return true;
146     }
147   }
148   return false;
149 }
150 
CanConnectToSocket(const char * name)151 bool CanConnectToSocket(const char* name) {
152   struct sockaddr_un addr = {};
153   addr.sun_family = AF_UNIX;
154   strncpy(addr.sun_path, name, sizeof(addr.sun_path) - 1);
155   int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
156   if (fd == -1) {
157     PLOG(ERROR) << "failed to create socket";
158     return false;
159   }
160   bool connected = connect(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) == 0;
161   close(fd);
162   return connected;
163 }
164 
165 constexpr size_t kMaxCmdlineSize = 512;
166 
167 class JavaHprofDataSource : public perfetto::DataSource<JavaHprofDataSource> {
168  public:
169   constexpr static perfetto::BufferExhaustedPolicy kBufferExhaustedPolicy =
170     perfetto::BufferExhaustedPolicy::kStall;
OnSetup(const SetupArgs & args)171   void OnSetup(const SetupArgs& args) override {
172     // This is on the heap as it triggers -Wframe-larger-than.
173     std::unique_ptr<perfetto::protos::pbzero::JavaHprofConfig::Decoder> cfg(
174         new perfetto::protos::pbzero::JavaHprofConfig::Decoder(
175           args.config->java_hprof_config_raw()));
176 
177     if (args.config->enable_extra_guardrails() && !CanConnectToSocket("/dev/socket/heapprofd")) {
178       LOG(ERROR) << "rejecting extra guardrails";
179       enabled_ = false;
180       return;
181     }
182 
183     dump_smaps_ = cfg->dump_smaps();
184 
185     uint64_t self_pid = static_cast<uint64_t>(getpid());
186     for (auto pid_it = cfg->pid(); pid_it; ++pid_it) {
187       if (*pid_it == self_pid) {
188         enabled_ = true;
189         return;
190       }
191     }
192 
193     if (cfg->has_process_cmdline()) {
194       int fd = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC);
195       if (fd == -1) {
196         PLOG(ERROR) << "failed to open /proc/self/cmdline";
197         return;
198       }
199       char cmdline[kMaxCmdlineSize];
200       ssize_t rd = read(fd, cmdline, sizeof(cmdline) - 1);
201       if (rd == -1) {
202         PLOG(ERROR) << "failed to read /proc/self/cmdline";
203       }
204       close(fd);
205       if (rd == -1) {
206         return;
207       }
208       cmdline[rd] = '\0';
209       char* cmdline_ptr = cmdline;
210       ssize_t sz = perfetto::profiling::NormalizeCmdLine(&cmdline_ptr, static_cast<size_t>(rd + 1));
211       if (sz == -1) {
212         PLOG(ERROR) << "failed to normalize cmdline";
213       }
214       for (auto it = cfg->process_cmdline(); it; ++it) {
215         std::string other = (*it).ToStdString();
216         // Append \0 to make this a C string.
217         other.resize(other.size() + 1);
218         char* other_ptr = &(other[0]);
219         ssize_t other_sz = perfetto::profiling::NormalizeCmdLine(&other_ptr, other.size());
220         if (other_sz == -1) {
221           PLOG(ERROR) << "failed to normalize other cmdline";
222           continue;
223         }
224         if (sz == other_sz && strncmp(cmdline_ptr, other_ptr, static_cast<size_t>(sz)) == 0) {
225           enabled_ = true;
226           return;
227         }
228       }
229     }
230   }
231 
dump_smaps()232   bool dump_smaps() { return dump_smaps_; }
enabled()233   bool enabled() { return enabled_; }
234 
OnStart(const StartArgs &)235   void OnStart(const StartArgs&) override {
236     if (!enabled()) {
237       return;
238     }
239     art::MutexLock lk(art_thread(), GetStateMutex());
240     if (g_state == State::kWaitForStart) {
241       g_state = State::kStart;
242       GetStateCV().Broadcast(art_thread());
243     }
244   }
245 
OnStop(const StopArgs &)246   void OnStop(const StopArgs&) override {}
247 
art_thread()248   static art::Thread* art_thread() {
249     // TODO(fmayer): Attach the Perfetto producer thread to ART and give it a name. This is
250     // not trivial, we cannot just attach the first time this method is called, because
251     // AttachCurrentThread deadlocks with the ConditionVariable::Wait in WaitForDataSource.
252     //
253     // We should attach the thread as soon as the Client API spawns it, but that needs more
254     // complicated plumbing.
255     return nullptr;
256   }
257 
258  private:
259   bool enabled_ = false;
260   bool dump_smaps_ = false;
261   static art::Thread* self_;
262 };
263 
264 art::Thread* JavaHprofDataSource::self_ = nullptr;
265 
266 
WaitForDataSource(art::Thread * self)267 void WaitForDataSource(art::Thread* self) {
268   perfetto::TracingInitArgs args;
269   args.backends = perfetto::BackendType::kSystemBackend;
270   perfetto::Tracing::Initialize(args);
271 
272   perfetto::DataSourceDescriptor dsd;
273   dsd.set_name("android.java_hprof");
274   JavaHprofDataSource::Register(dsd);
275 
276   LOG(INFO) << "waiting for data source";
277 
278   art::MutexLock lk(self, GetStateMutex());
279   while (g_state != State::kStart) {
280     GetStateCV().Wait(self);
281   }
282 }
283 
284 class Writer {
285  public:
Writer(pid_t parent_pid,JavaHprofDataSource::TraceContext * ctx,uint64_t timestamp)286   Writer(pid_t parent_pid, JavaHprofDataSource::TraceContext* ctx, uint64_t timestamp)
287       : parent_pid_(parent_pid), ctx_(ctx), timestamp_(timestamp),
288         last_written_(ctx_->written()) {}
289 
290   // Return whether the next call to GetHeapGraph will create a new TracePacket.
will_create_new_packet()291   bool will_create_new_packet() {
292     return !heap_graph_ || ctx_->written() - last_written_ > kPacketSizeThreshold;
293   }
294 
GetHeapGraph()295   perfetto::protos::pbzero::HeapGraph* GetHeapGraph() {
296     if (will_create_new_packet()) {
297       CreateNewHeapGraph();
298     }
299     return heap_graph_;
300   }
301 
CreateNewHeapGraph()302   void CreateNewHeapGraph() {
303     if (heap_graph_) {
304       heap_graph_->set_continued(true);
305     }
306     Finalize();
307 
308     uint64_t written = ctx_->written();
309 
310     trace_packet_ = ctx_->NewTracePacket();
311     trace_packet_->set_timestamp(timestamp_);
312     heap_graph_ = trace_packet_->set_heap_graph();
313     heap_graph_->set_pid(parent_pid_);
314     heap_graph_->set_index(index_++);
315 
316     last_written_ = written;
317   }
318 
Finalize()319   void Finalize() {
320     if (trace_packet_) {
321       trace_packet_->Finalize();
322     }
323     heap_graph_ = nullptr;
324   }
325 
~Writer()326   ~Writer() { Finalize(); }
327 
328  private:
329   const pid_t parent_pid_;
330   JavaHprofDataSource::TraceContext* const ctx_;
331   const uint64_t timestamp_;
332 
333   uint64_t last_written_ = 0;
334 
335   perfetto::DataSource<JavaHprofDataSource>::TraceContext::TracePacketHandle
336       trace_packet_;
337   perfetto::protos::pbzero::HeapGraph* heap_graph_ = nullptr;
338 
339   uint64_t index_ = 0;
340 };
341 
342 class ReferredObjectsFinder {
343  public:
ReferredObjectsFinder(std::vector<std::pair<std::string,art::mirror::Object * >> * referred_objects)344   explicit ReferredObjectsFinder(
345       std::vector<std::pair<std::string, art::mirror::Object*>>* referred_objects)
346       : referred_objects_(referred_objects) {}
347 
348   // For art::mirror::Object::VisitReferences.
operator ()(art::ObjPtr<art::mirror::Object> obj,art::MemberOffset offset,bool is_static) const349   void operator()(art::ObjPtr<art::mirror::Object> obj, art::MemberOffset offset,
350                   bool is_static) const
351       REQUIRES_SHARED(art::Locks::mutator_lock_) {
352     art::mirror::Object* ref = obj->GetFieldObject<art::mirror::Object>(offset);
353     art::ArtField* field;
354     if (is_static) {
355       field = art::ArtField::FindStaticFieldWithOffset(obj->AsClass(), offset.Uint32Value());
356     } else {
357       field = art::ArtField::FindInstanceFieldWithOffset(obj->GetClass(), offset.Uint32Value());
358     }
359     std::string field_name = "";
360     if (field != nullptr) {
361       field_name = field->PrettyField(/*with_type=*/true);
362     }
363     referred_objects_->emplace_back(std::move(field_name), ref);
364   }
365 
VisitRootIfNonNull(art::mirror::CompressedReference<art::mirror::Object> * root ATTRIBUTE_UNUSED) const366   void VisitRootIfNonNull(art::mirror::CompressedReference<art::mirror::Object>* root
367                               ATTRIBUTE_UNUSED) const {}
VisitRoot(art::mirror::CompressedReference<art::mirror::Object> * root ATTRIBUTE_UNUSED) const368   void VisitRoot(art::mirror::CompressedReference<art::mirror::Object>* root
369                      ATTRIBUTE_UNUSED) const {}
370 
371  private:
372   // We can use a raw Object* pointer here, because there are no concurrent GC threads after the
373   // fork.
374   std::vector<std::pair<std::string, art::mirror::Object*>>* referred_objects_;
375 };
376 
377 class RootFinder : public art::SingleRootVisitor {
378  public:
RootFinder(std::map<art::RootType,std::vector<art::mirror::Object * >> * root_objects)379   explicit RootFinder(
380     std::map<art::RootType, std::vector<art::mirror::Object*>>* root_objects)
381       : root_objects_(root_objects) {}
382 
VisitRoot(art::mirror::Object * root,const art::RootInfo & info)383   void VisitRoot(art::mirror::Object* root, const art::RootInfo& info) override {
384     (*root_objects_)[info.GetType()].emplace_back(root);
385   }
386 
387  private:
388   // We can use a raw Object* pointer here, because there are no concurrent GC threads after the
389   // fork.
390   std::map<art::RootType, std::vector<art::mirror::Object*>>* root_objects_;
391 };
392 
ToProtoType(art::RootType art_type)393 perfetto::protos::pbzero::HeapGraphRoot::Type ToProtoType(art::RootType art_type) {
394   switch (art_type) {
395     case art::kRootUnknown:
396       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_UNKNOWN;
397     case art::kRootJNIGlobal:
398       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_JNI_GLOBAL;
399     case art::kRootJNILocal:
400       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_JNI_LOCAL;
401     case art::kRootJavaFrame:
402       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_JAVA_FRAME;
403     case art::kRootNativeStack:
404       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_NATIVE_STACK;
405     case art::kRootStickyClass:
406       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_STICKY_CLASS;
407     case art::kRootThreadBlock:
408       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_THREAD_BLOCK;
409     case art::kRootMonitorUsed:
410       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_MONITOR_USED;
411     case art::kRootThreadObject:
412       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_THREAD_OBJECT;
413     case art::kRootInternedString:
414       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_INTERNED_STRING;
415     case art::kRootFinalizing:
416       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_FINALIZING;
417     case art::kRootDebugger:
418       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_DEBUGGER;
419     case art::kRootReferenceCleanup:
420       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_REFERENCE_CLEANUP;
421     case art::kRootVMInternal:
422       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_VM_INTERNAL;
423     case art::kRootJNIMonitor:
424       return perfetto::protos::pbzero::HeapGraphRoot::ROOT_JNI_MONITOR;
425   }
426 }
427 
PrettyType(art::mirror::Class * klass)428 std::string PrettyType(art::mirror::Class* klass) NO_THREAD_SAFETY_ANALYSIS {
429   if (klass == nullptr) {
430     return "(raw)";
431   }
432   std::string temp;
433   std::string result(art::PrettyDescriptor(klass->GetDescriptor(&temp)));
434   return result;
435 }
436 
DumpSmaps(JavaHprofDataSource::TraceContext * ctx)437 void DumpSmaps(JavaHprofDataSource::TraceContext* ctx) {
438   FILE* smaps = fopen("/proc/self/smaps", "r");
439   if (smaps != nullptr) {
440     auto trace_packet = ctx->NewTracePacket();
441     auto* smaps_packet = trace_packet->set_smaps_packet();
442     smaps_packet->set_pid(getpid());
443     perfetto::profiling::ParseSmaps(smaps,
444         [&smaps_packet](const perfetto::profiling::SmapsEntry& e) {
445       if (ShouldSampleSmapsEntry(e)) {
446         auto* smaps_entry = smaps_packet->add_entries();
447         smaps_entry->set_path(e.pathname);
448         smaps_entry->set_size_kb(e.size_kb);
449         smaps_entry->set_private_dirty_kb(e.private_dirty_kb);
450         smaps_entry->set_swap_kb(e.swap_kb);
451       }
452     });
453     fclose(smaps);
454   } else {
455     PLOG(ERROR) << "failed to open smaps";
456   }
457 }
458 
GetObjectId(const art::mirror::Object * obj)459 uint64_t GetObjectId(const art::mirror::Object* obj) {
460   return reinterpret_cast<uint64_t>(obj) / std::alignment_of<art::mirror::Object>::value;
461 }
462 
DumpPerfetto(art::Thread * self)463 void DumpPerfetto(art::Thread* self) {
464   pid_t parent_pid = getpid();
465   LOG(INFO) << "preparing to dump heap for " << parent_pid;
466 
467   // Need to take a heap dump while GC isn't running. See the comment in
468   // Heap::VisitObjects(). Also we need the critical section to avoid visiting
469   // the same object twice. See b/34967844.
470   //
471   // We need to do this before the fork, because otherwise it can deadlock
472   // waiting for the GC, as all other threads get terminated by the clone, but
473   // their locks are not released.
474   art::gc::ScopedGCCriticalSection gcs(self, art::gc::kGcCauseHprof,
475                                        art::gc::kCollectorTypeHprof);
476 
477   art::ScopedSuspendAll ssa(__FUNCTION__, /* long_suspend=*/ true);
478 
479   pid_t pid = fork();
480   if (pid == -1) {
481     // Fork error.
482     PLOG(ERROR) << "fork";
483     return;
484   }
485   if (pid != 0) {
486     // Parent
487     int stat_loc;
488     for (;;) {
489       if (waitpid(pid, &stat_loc, 0) != -1 || errno != EINTR) {
490         break;
491       }
492     }
493     return;
494   }
495 
496   // The following code is only executed by the child of the original process.
497   //
498   // Daemon creates a new process that is the grand-child of the original process, and exits.
499   if (daemon(0, 0) == -1) {
500     PLOG(FATAL) << "daemon";
501   }
502 
503   // The following code is only executed by the grand-child of the original process.
504 
505   // Make sure that this is the first thing we do after forking, so if anything
506   // below hangs, the fork will go away from the watchdog.
507   ArmWatchdogOrDie();
508 
509   struct timespec ts = {};
510   if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) {
511     LOG(FATAL) << "Failed to get boottime.";
512   }
513   uint64_t timestamp = ts.tv_sec * 1000000000LL + ts.tv_nsec;
514 
515   WaitForDataSource(self);
516 
517   JavaHprofDataSource::Trace(
518       [parent_pid, timestamp](JavaHprofDataSource::TraceContext ctx)
519           NO_THREAD_SAFETY_ANALYSIS {
520             bool dump_smaps;
521             {
522               auto ds = ctx.GetDataSourceLocked();
523               if (!ds || !ds->enabled()) {
524                 LOG(INFO) << "skipping irrelevant data source.";
525                 return;
526               }
527               dump_smaps = ds->dump_smaps();
528             }
529             LOG(INFO) << "dumping heap for " << parent_pid;
530             if (dump_smaps) {
531               DumpSmaps(&ctx);
532             }
533             Writer writer(parent_pid, &ctx, timestamp);
534             // Make sure that intern ID 0 (default proto value for a uint64_t) always maps to ""
535             // (default proto value for a string).
536             std::map<std::string, uint64_t> interned_fields{{"", 0}};
537             std::map<std::string, uint64_t> interned_locations{{"", 0}};
538             std::map<uintptr_t, uint64_t> interned_classes{{0, 0}};
539 
540             std::map<art::RootType, std::vector<art::mirror::Object*>> root_objects;
541             RootFinder rcf(&root_objects);
542             art::Runtime::Current()->VisitRoots(&rcf);
543             std::unique_ptr<protozero::PackedVarInt> object_ids(
544                 new protozero::PackedVarInt);
545             for (const auto& p : root_objects) {
546               const art::RootType root_type = p.first;
547               const std::vector<art::mirror::Object*>& children = p.second;
548               perfetto::protos::pbzero::HeapGraphRoot* root_proto =
549                 writer.GetHeapGraph()->add_roots();
550               root_proto->set_root_type(ToProtoType(root_type));
551               for (art::mirror::Object* obj : children) {
552                 if (writer.will_create_new_packet()) {
553                   root_proto->set_object_ids(*object_ids);
554                   object_ids->Reset();
555                   root_proto = writer.GetHeapGraph()->add_roots();
556                   root_proto->set_root_type(ToProtoType(root_type));
557                 }
558                 object_ids->Append(GetObjectId(obj));
559               }
560               root_proto->set_object_ids(*object_ids);
561               object_ids->Reset();
562             }
563 
564             std::unique_ptr<protozero::PackedVarInt> reference_field_ids(
565                 new protozero::PackedVarInt);
566             std::unique_ptr<protozero::PackedVarInt> reference_object_ids(
567                 new protozero::PackedVarInt);
568 
569             art::Runtime::Current()->GetHeap()->VisitObjectsPaused(
570                 [&writer, &interned_fields, &interned_locations,
571                 &reference_field_ids, &reference_object_ids, &interned_classes](
572                     art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
573                   if (obj->IsClass()) {
574                     art::mirror::Class* klass = obj->AsClass().Ptr();
575                     perfetto::protos::pbzero::HeapGraphType* type_proto =
576                       writer.GetHeapGraph()->add_types();
577                     type_proto->set_id(FindOrAppend(&interned_classes,
578                           reinterpret_cast<uintptr_t>(klass)));
579                     type_proto->set_class_name(PrettyType(klass));
580                     type_proto->set_location_id(FindOrAppend(&interned_locations,
581                           klass->GetLocation()));
582                     type_proto->set_object_size(klass->GetObjectSize());
583                   }
584 
585                   art::mirror::Class* klass = obj->GetClass();
586                   uintptr_t class_ptr = reinterpret_cast<uintptr_t>(klass);
587                   // We need to synethesize a new type for Class<Foo>, which does not exist
588                   // in the runtime. Otherwise, all the static members of all classes would be
589                   // attributed to java.lang.Class.
590                   if (klass->IsClassClass()) {
591                     CHECK(obj->IsClass());
592                     perfetto::protos::pbzero::HeapGraphType* type_proto =
593                       writer.GetHeapGraph()->add_types();
594                     // All pointers are at least multiples of two, so this way we can make sure
595                     // we are not colliding with a real class.
596                     class_ptr = reinterpret_cast<uintptr_t>(obj) | 1;
597                     auto class_id = FindOrAppend(&interned_classes, class_ptr);
598                     type_proto->set_id(class_id);
599                     type_proto->set_class_name(obj->PrettyTypeOf());
600                     type_proto->set_location_id(FindOrAppend(&interned_locations,
601                           obj->AsClass()->GetLocation()));
602                   }
603 
604                   auto class_id = FindOrAppend(&interned_classes, class_ptr);
605 
606                   perfetto::protos::pbzero::HeapGraphObject* object_proto =
607                     writer.GetHeapGraph()->add_objects();
608                   object_proto->set_id(GetObjectId(obj));
609                   object_proto->set_type_id(class_id);
610 
611                   // Arrays / strings are magic and have an instance dependent size.
612                   if (obj->SizeOf() != klass->GetObjectSize())
613                     object_proto->set_self_size(obj->SizeOf());
614 
615                   std::vector<std::pair<std::string, art::mirror::Object*>>
616                       referred_objects;
617                   ReferredObjectsFinder objf(&referred_objects);
618                   obj->VisitReferences(objf, art::VoidFunctor());
619                   for (const auto& p : referred_objects) {
620                     reference_field_ids->Append(FindOrAppend(&interned_fields, p.first));
621                     reference_object_ids->Append(GetObjectId(p.second));
622                   }
623                   object_proto->set_reference_field_id(*reference_field_ids);
624                   object_proto->set_reference_object_id(*reference_object_ids);
625                   reference_field_ids->Reset();
626                   reference_object_ids->Reset();
627                 });
628 
629             for (const auto& p : interned_fields) {
630               const std::string& str = p.first;
631               uint64_t id = p.second;
632 
633               perfetto::protos::pbzero::InternedString* field_proto =
634                 writer.GetHeapGraph()->add_field_names();
635               field_proto->set_iid(id);
636               field_proto->set_str(
637                   reinterpret_cast<const uint8_t*>(str.c_str()), str.size());
638             }
639             for (const auto& p : interned_locations) {
640               const std::string& str = p.first;
641               uint64_t id = p.second;
642 
643               perfetto::protos::pbzero::InternedString* location_proto =
644                 writer.GetHeapGraph()->add_location_names();
645               location_proto->set_iid(id);
646               location_proto->set_str(reinterpret_cast<const uint8_t*>(str.c_str()),
647                                   str.size());
648             }
649 
650             writer.Finalize();
651 
652             ctx.Flush([] {
653               {
654                 art::MutexLock lk(JavaHprofDataSource::art_thread(), GetStateMutex());
655                 g_state = State::kEnd;
656                 GetStateCV().Broadcast(JavaHprofDataSource::art_thread());
657               }
658             });
659           });
660 
661   art::MutexLock lk(self, GetStateMutex());
662   while (g_state != State::kEnd) {
663     GetStateCV().Wait(self);
664   }
665   LOG(INFO) << "finished dumping heap for " << parent_pid;
666   // Prevent the atexit handlers to run. We do not want to call cleanup
667   // functions the parent process has registered.
668   _exit(0);
669 }
670 
671 // The plugin initialization function.
ArtPlugin_Initialize()672 extern "C" bool ArtPlugin_Initialize() {
673   if (art::Runtime::Current() == nullptr) {
674     return false;
675   }
676   art::Thread* self = art::Thread::Current();
677   {
678     art::MutexLock lk(self, GetStateMutex());
679     if (g_state != State::kUninitialized) {
680       LOG(ERROR) << "perfetto_hprof already initialized. state: " << g_state;
681       return false;
682     }
683     g_state = State::kWaitForListener;
684   }
685 
686   if (pipe2(g_signal_pipe_fds, O_CLOEXEC) == -1) {
687     PLOG(ERROR) << "Failed to pipe";
688     return false;
689   }
690 
691   struct sigaction act = {};
692   act.sa_flags = SA_SIGINFO | SA_RESTART;
693   act.sa_sigaction = [](int, siginfo_t*, void*) {
694     if (write(g_signal_pipe_fds[1], kByte, sizeof(kByte)) == -1) {
695       PLOG(ERROR) << "Failed to trigger heap dump";
696     }
697   };
698 
699   // TODO(fmayer): We can probably use the SignalCatcher thread here to not
700   // have an idle thread.
701   if (sigaction(kJavaHeapprofdSignal, &act, &g_orig_act) != 0) {
702     close(g_signal_pipe_fds[0]);
703     close(g_signal_pipe_fds[1]);
704     PLOG(ERROR) << "Failed to sigaction";
705     return false;
706   }
707 
708   std::thread th([] {
709     art::Runtime* runtime = art::Runtime::Current();
710     if (!runtime) {
711       LOG(FATAL_WITHOUT_ABORT) << "no runtime in perfetto_hprof_listener";
712       return;
713     }
714     if (!runtime->AttachCurrentThread("perfetto_hprof_listener", /*as_daemon=*/ true,
715                                       runtime->GetSystemThreadGroup(), /*create_peer=*/ false)) {
716       LOG(ERROR) << "failed to attach thread.";
717       {
718         art::MutexLock lk(nullptr, GetStateMutex());
719         g_state = State::kUninitialized;
720         GetStateCV().Broadcast(nullptr);
721       }
722 
723       return;
724     }
725     art::Thread* self = art::Thread::Current();
726     if (!self) {
727       LOG(FATAL_WITHOUT_ABORT) << "no thread in perfetto_hprof_listener";
728       return;
729     }
730     {
731       art::MutexLock lk(self, GetStateMutex());
732       if (g_state == State::kWaitForListener) {
733         g_state = State::kWaitForStart;
734         GetStateCV().Broadcast(self);
735       }
736     }
737     char buf[1];
738     for (;;) {
739       int res;
740       do {
741         res = read(g_signal_pipe_fds[0], buf, sizeof(buf));
742       } while (res == -1 && errno == EINTR);
743 
744       if (res <= 0) {
745         if (res == -1) {
746           PLOG(ERROR) << "failed to read";
747         }
748         close(g_signal_pipe_fds[0]);
749         return;
750       }
751 
752       perfetto_hprof::DumpPerfetto(self);
753     }
754   });
755   th.detach();
756 
757   return true;
758 }
759 
ArtPlugin_Deinitialize()760 extern "C" bool ArtPlugin_Deinitialize() {
761   if (sigaction(kJavaHeapprofdSignal, &g_orig_act, nullptr) != 0) {
762     PLOG(ERROR) << "failed to reset signal handler";
763     // We cannot close the pipe if the signal handler wasn't unregistered,
764     // to avoid receiving SIGPIPE.
765     return false;
766   }
767   close(g_signal_pipe_fds[1]);
768 
769   art::Thread* self = art::Thread::Current();
770   art::MutexLock lk(self, GetStateMutex());
771   // Wait until after the thread was registered to the runtime. This is so
772   // we do not attempt to register it with the runtime after it had been torn
773   // down (ArtPlugin_Deinitialize gets called in the Runtime dtor).
774   while (g_state == State::kWaitForListener) {
775     GetStateCV().Wait(art::Thread::Current());
776   }
777   g_state = State::kUninitialized;
778   GetStateCV().Broadcast(self);
779   return true;
780 }
781 
782 }  // namespace perfetto_hprof
783 
784 namespace perfetto {
785 
786 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(perfetto_hprof::JavaHprofDataSource);
787 
788 }
789