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                   }
583 
584                   art::mirror::Class* klass = obj->GetClass();
585                   uintptr_t class_ptr = reinterpret_cast<uintptr_t>(klass);
586                   // We need to synethesize a new type for Class<Foo>, which does not exist
587                   // in the runtime. Otherwise, all the static members of all classes would be
588                   // attributed to java.lang.Class.
589                   if (klass->IsClassClass()) {
590                     CHECK(obj->IsClass());
591                     perfetto::protos::pbzero::HeapGraphType* type_proto =
592                       writer.GetHeapGraph()->add_types();
593                     // All pointers are at least multiples of two, so this way we can make sure
594                     // we are not colliding with a real class.
595                     class_ptr = reinterpret_cast<uintptr_t>(obj) | 1;
596                     auto class_id = FindOrAppend(&interned_classes, class_ptr);
597                     type_proto->set_id(class_id);
598                     type_proto->set_class_name(obj->PrettyTypeOf());
599                     type_proto->set_location_id(FindOrAppend(&interned_locations,
600                           obj->AsClass()->GetLocation()));
601                   }
602 
603                   auto class_id = FindOrAppend(&interned_classes, class_ptr);
604 
605                   perfetto::protos::pbzero::HeapGraphObject* object_proto =
606                     writer.GetHeapGraph()->add_objects();
607                   object_proto->set_id(GetObjectId(obj));
608                   object_proto->set_type_id(class_id);
609                   object_proto->set_self_size(obj->SizeOf());
610 
611                   std::vector<std::pair<std::string, art::mirror::Object*>>
612                       referred_objects;
613                   ReferredObjectsFinder objf(&referred_objects);
614                   obj->VisitReferences(objf, art::VoidFunctor());
615                   for (const auto& p : referred_objects) {
616                     reference_field_ids->Append(FindOrAppend(&interned_fields, p.first));
617                     reference_object_ids->Append(GetObjectId(p.second));
618                   }
619                   object_proto->set_reference_field_id(*reference_field_ids);
620                   object_proto->set_reference_object_id(*reference_object_ids);
621                   reference_field_ids->Reset();
622                   reference_object_ids->Reset();
623                 });
624 
625             for (const auto& p : interned_fields) {
626               const std::string& str = p.first;
627               uint64_t id = p.second;
628 
629               perfetto::protos::pbzero::InternedString* field_proto =
630                 writer.GetHeapGraph()->add_field_names();
631               field_proto->set_iid(id);
632               field_proto->set_str(
633                   reinterpret_cast<const uint8_t*>(str.c_str()), str.size());
634             }
635             for (const auto& p : interned_locations) {
636               const std::string& str = p.first;
637               uint64_t id = p.second;
638 
639               perfetto::protos::pbzero::InternedString* location_proto =
640                 writer.GetHeapGraph()->add_location_names();
641               location_proto->set_iid(id);
642               location_proto->set_str(reinterpret_cast<const uint8_t*>(str.c_str()),
643                                   str.size());
644             }
645 
646             writer.Finalize();
647 
648             ctx.Flush([] {
649               {
650                 art::MutexLock lk(JavaHprofDataSource::art_thread(), GetStateMutex());
651                 g_state = State::kEnd;
652                 GetStateCV().Broadcast(JavaHprofDataSource::art_thread());
653               }
654             });
655           });
656 
657   art::MutexLock lk(self, GetStateMutex());
658   while (g_state != State::kEnd) {
659     GetStateCV().Wait(self);
660   }
661   LOG(INFO) << "finished dumping heap for " << parent_pid;
662   // Prevent the atexit handlers to run. We do not want to call cleanup
663   // functions the parent process has registered.
664   _exit(0);
665 }
666 
667 // The plugin initialization function.
ArtPlugin_Initialize()668 extern "C" bool ArtPlugin_Initialize() {
669   if (art::Runtime::Current() == nullptr) {
670     return false;
671   }
672   art::Thread* self = art::Thread::Current();
673   {
674     art::MutexLock lk(self, GetStateMutex());
675     if (g_state != State::kUninitialized) {
676       LOG(ERROR) << "perfetto_hprof already initialized. state: " << g_state;
677       return false;
678     }
679     g_state = State::kWaitForListener;
680   }
681 
682   if (pipe2(g_signal_pipe_fds, O_CLOEXEC) == -1) {
683     PLOG(ERROR) << "Failed to pipe";
684     return false;
685   }
686 
687   struct sigaction act = {};
688   act.sa_flags = SA_SIGINFO | SA_RESTART;
689   act.sa_sigaction = [](int, siginfo_t*, void*) {
690     if (write(g_signal_pipe_fds[1], kByte, sizeof(kByte)) == -1) {
691       PLOG(ERROR) << "Failed to trigger heap dump";
692     }
693   };
694 
695   // TODO(fmayer): We can probably use the SignalCatcher thread here to not
696   // have an idle thread.
697   if (sigaction(kJavaHeapprofdSignal, &act, &g_orig_act) != 0) {
698     close(g_signal_pipe_fds[0]);
699     close(g_signal_pipe_fds[1]);
700     PLOG(ERROR) << "Failed to sigaction";
701     return false;
702   }
703 
704   std::thread th([] {
705     art::Runtime* runtime = art::Runtime::Current();
706     if (!runtime) {
707       LOG(FATAL_WITHOUT_ABORT) << "no runtime in perfetto_hprof_listener";
708       return;
709     }
710     if (!runtime->AttachCurrentThread("perfetto_hprof_listener", /*as_daemon=*/ true,
711                                       runtime->GetSystemThreadGroup(), /*create_peer=*/ false)) {
712       LOG(ERROR) << "failed to attach thread.";
713       {
714         art::MutexLock lk(nullptr, GetStateMutex());
715         g_state = State::kUninitialized;
716         GetStateCV().Broadcast(nullptr);
717       }
718 
719       return;
720     }
721     art::Thread* self = art::Thread::Current();
722     if (!self) {
723       LOG(FATAL_WITHOUT_ABORT) << "no thread in perfetto_hprof_listener";
724       return;
725     }
726     {
727       art::MutexLock lk(self, GetStateMutex());
728       if (g_state == State::kWaitForListener) {
729         g_state = State::kWaitForStart;
730         GetStateCV().Broadcast(self);
731       }
732     }
733     char buf[1];
734     for (;;) {
735       int res;
736       do {
737         res = read(g_signal_pipe_fds[0], buf, sizeof(buf));
738       } while (res == -1 && errno == EINTR);
739 
740       if (res <= 0) {
741         if (res == -1) {
742           PLOG(ERROR) << "failed to read";
743         }
744         close(g_signal_pipe_fds[0]);
745         return;
746       }
747 
748       perfetto_hprof::DumpPerfetto(self);
749     }
750   });
751   th.detach();
752 
753   return true;
754 }
755 
ArtPlugin_Deinitialize()756 extern "C" bool ArtPlugin_Deinitialize() {
757   if (sigaction(kJavaHeapprofdSignal, &g_orig_act, nullptr) != 0) {
758     PLOG(ERROR) << "failed to reset signal handler";
759     // We cannot close the pipe if the signal handler wasn't unregistered,
760     // to avoid receiving SIGPIPE.
761     return false;
762   }
763   close(g_signal_pipe_fds[1]);
764 
765   art::Thread* self = art::Thread::Current();
766   art::MutexLock lk(self, GetStateMutex());
767   // Wait until after the thread was registered to the runtime. This is so
768   // we do not attempt to register it with the runtime after it had been torn
769   // down (ArtPlugin_Deinitialize gets called in the Runtime dtor).
770   while (g_state == State::kWaitForListener) {
771     GetStateCV().Wait(art::Thread::Current());
772   }
773   g_state = State::kUninitialized;
774   GetStateCV().Broadcast(self);
775   return true;
776 }
777 
778 }  // namespace perfetto_hprof
779 
780 namespace perfetto {
781 
782 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(perfetto_hprof::JavaHprofDataSource);
783 
784 }
785